c++RTTI

本文介绍了C++中的运行时类型识别(RTTI)特性,包括RTTI的工作原理、dynamic_cast运算符、typeid运算符和type_info类的使用。RTTI主要用于类层次结构中基类指针指向派生类对象的情况,允许安全地转换类型并获取对象的准确类型信息。文章通过示例代码展示了如何有效和避免误用RTTI。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

1.RTTI是运行阶段类型识别的简称。这是新添加到c++中的特性之一。

2.用途:假设有一个类层次结构,其中的类都是从同一个基类派生而来的,则可以让基类指针指向其中任何一个类的对象。这样就可以调用这些函数:处理信息后,选择哪个类,并创建这种类型的对象,然后返回它的地址,而该地址可以被赋给基类指针。如何知道指针指向的是那种对象呢?

在了解答案前,应考虑为何要知道类型。可能希望调用类方法的正确版本,在这种情况下,只要该函数是类层次结构中所有成员都拥有的虚函数,则并不希望需要知道对象的类型。但派生对象可能包含不是继承而来的方法,在这种情况下,只有某些类型的对象可以使用该方法,也可能是出于调式目的,想知道生成对象的类型。RTTI提供解决方案。

RTTI的工作原理

c++有3个支持RTTI的元素

  1. 如果可能的话,dynameic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针;否则,该运算符返回0-空指针。
  2. typeid运算符返回一个指出对象的类型的值。
  3. type_info结构存储了有关特定类型的信息。

只能将RTTI用于包含虚函数的类层次结构,原因在于只有对于这种类层次结构,才应该将派生对象的地址赋给基类指针。

注:RTTI只适用于包含虚函数的类。

dynamic_cast运算符

dynamic_cast运算符是最常用的RTTI组件,作用:安全地将对象的地址赋给特定类型的指针。例:

class Grand{
   //虚函数};
class Superb:public Grand{
   ...};
class Magnificent:public Superb{
   ...};

假设有下面的指针:

Grand * pg =new Grand;
Grand * ps = new Superb;
Grand * pm = new Magnificent;

最后,对于下面的类型转换:

Magnificent * p1 = (Magnificent *) pm;//安全;将Magnificent类型的指针指向类型为Magnificent的对象
Magnificent *  p2=(Magnificent *) pg;//不安全;将基数对象Grand的地址赋给派生类Magnificent指针。例如:Magnificent中可能包含一些Grand对象没有的数据成员
Superb * p3= (Magnificent *) pm;//安全,将派生对象的地址赋给基类指针。即公有派生确保Magnificent对象同时也是Superb对象(直接基类)和一个Grand(间接基类)。
  1. 只有指针类型与对象的类型(或对象的直接或间接基类的类型)相同的类型转换才一定是安全的。

  2. 虚函数确保了将三种指针中的任何一种指向Magnificent对象时,都将调用Magnificent方法。

  3. 相比指针指向得是那种类型的对象,类型转换是否安全更通用,也更有用。

  4. 通常想知道类型的原因在于:知道类型后,就知道调用特定的方法是否安全,要调用方法,类型并不一定要完全匹配,而是定义了方法的虚拟版本的基类类型。
    例:
    dynamic_cast的语法:

Superb * pm = dynamic_cast<Superb *>(pg);

指针pg的类型是否可被安全地转换为Superb*?如果可以,运算符将返回对象的地址,否则返回一个空指针。

注:如果指向的对象(*pt)的类型为Type或者是从Type直接或间接派生而来的类型,则下面的表达式将指针pt转换为Type类型的指针:

dynamic_cast<Type *>(pt)

否则,结果为0,即空指针。

例:

#include <iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
class Grand
{
   
private:
    int hold;
public:
    Grand(int h=0):hold(h){
   }
    virtual void Speak()const{
   cout<<"I am a grand class!\n";}
    virtual int Value()const{
   return hold;}
};

class Superb:public Grand
{
   
public:
    Superb(int h=0):Grand(h){
   }
 void Speak()
### 关于C++运行时类型信息(RTTI) C++中的RTTI(Run-Time Type Information),即运行时类型信息,是一种允许程序在执行期间查询对象类型的机制。它通过`typeid`, `dynamic_cast`, 和 `type_info` 类来实现。 #### 使用 `typeid` `typeid` 是一种用于获取对象或表达式的具体类型的操作符。它可以返回一个 `std::type_info` 对象的引用,该对象包含了关于所请求类型的编译期和运行时期的信息[^1]。 ```cpp #include <iostream> #include <typeinfo> class Base { public: virtual ~Base() {} }; class Derived : public Base {}; int main() { Base* basePtr = new Derived(); std::cout << "Type of *basePtr: " << typeid(*basePtr).name() << "\n"; // 输出实际的对象类型 delete basePtr; } ``` 上述代码展示了如何利用 `typeid` 来判断指针指向的实际对象类型。注意,为了使 `typeid` 能够区分派生类和基类实例,基类必须至少有一个虚函数。 #### 动态转换 (`dynamic_cast`) 当需要安全地将基类指针或引用转换为派生类指针或引用时,可以使用 `dynamic_cast`。如果转换失败,则会返回空指针或者抛出异常(对于引用而言)。这使得程序员可以在运行时验证类型的安全性。 ```cpp Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); if(derivedPtr != nullptr){ // 成功转换到 Derived* } else { // 失败处理逻辑 } ``` 动态转换仅适用于多态类型之间;也就是说,只有存在虚拟成员函数的情况下才能生效。 #### 总结 尽管 RTTI 提供了强大的功能,但在某些高性能需求场景下可能被认为开销过大而被禁用。因此,在游戏开发等领域中需谨慎考虑其应用场合[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值