首页 > 代码库 > c++中RTTI

c++中RTTI

  RTTI 是“Runtime Type Information”的缩写,意思是:运行时类型信息。它提供了运行时确定对象类型的方法。本文将简略介绍 RTTI 的一些背景知识、描述 RTTI 的概念,并通过具体例子和代码介绍什么时候使用以及如何使用 RTTI;本文还将详细描述两个重要的 RTTI 运算符的使用方法,它们是 typeid 和 dynamic_cast。如何确定对象的动态类型呢?答案是使用内建的 RTTI 中的运算符:typeid 和 dynamic_cast。

  typeid的主要作用就是让用户知道当前的变量是什么类型的,对于我们自定义的结构体和类,tpyeid都能支持。

 typeid是C++的关键字之一,等同于sizeof这类的操作符。typeid操作符的返回结果是名为type_info的标准库类型的对象的引用,它的表达式有下图两种形式。

技术分享

如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。ISO C++标准并没有确切定义type_info,它的确切定义编译器相关的,但是标准却规定了其实现必需提供如下四种操作(在之后的章节中我会来分析type_info类文件的源码):

 t1 == t2  如果两个对象t1和t2类型相同,则返回true;否则返回false
 t1 != t2  如果两个对象t1和t2类型不同,则返回true;否则返回false
 t.name()  返回类型的C-style字符串,类型名字用系统相关的方法产生
 t1.before(t2)  返回指出t1是否出现在t2之前的bool值
#include <iostream>
using namespace std;

class Base {};
class Derived: public Base {};

int main()
{
    Base b, *pb;
    pb = NULL;
    Derived d;

    cout << typeid(int).name() << endl
         << typeid(unsigned).name() << endl
         << typeid(long).name() << endl
         << typeid(unsigned long).name() << endl
         << typeid(char).name() << endl
         << typeid(unsigned char).name() << endl
         << typeid(float).name() << endl
         << typeid(double).name() << endl
         << typeid(string).name() << endl
         << typeid(Base).name() << endl
         << typeid(b).name()<<endl
         << typeid(pb).name()<<endl
         << typeid(Derived).name() << endl
         << typeid(d).name()<<endl
         << typeid(type_info).name() << endl;
         
    return 0;
}

 运行结果:技术分享

dynamic_cast 操作符,将基类的指针或引用安全的转换为派生类的指针或引用
1. 原理:将一个基类对象指针(或引用)cast (抛)到继承类指针,dynamic_cast 会根据基类指针是否真正指向继承类指针来做相应处理。

2. 返回值:对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针;对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。 

3. 注意:dynamic_cast在将父类cast到子类时,父类必须要有虚函数。
在c++中使用dynamic_cast进行类型转换属于向下类型,即将基类类型转换为派生类类型,向上类型转换编译器可以自动完成。
下面的代码说明了C++中RTTI运行机制。
#include <iostream>
#include <typeinfo>

using namespace std;

class base
{
public:

   virtual  void funA() {cout<<"Base "<<endl;}
};

class derived : public base
{
public:
    virtual  void funB() {  cout<<"derived "<<endl;}
};

void funcC(base* p)
{
    derived* dp=dynamic_cast<derived*>(p);
    if(dp!=NULL)
        dp->funB();
    else
        p->funA();

}

void funcD(base* p)
{
    derived* dp=NULL;
    if(typeid(*p)==typeid(derived))
    {
        dp=static_cast<derived*>(p);
        dp->funB();
    }
    else
        p->funA();

}

int main()
{

    base *cp=new derived;//向上类型转换,系统自动完成,指针cp指向derived中继承base部分
    cout<<typeid(cp).name()<<endl;//class base*
    cout<<typeid(*cp).name()<<endl;//class derived
    funcD(cp); //typeid(*cp)==typeid(derived),使用static_cast<derived*>(cp)也可以将基类转换为派生类,是在编译时完成,而dynamic_cast是在运行时处理的
    funcC(cp);//采用dynamic_cast完成基类到派生类的转换,转换成功
    base* dp=new base;
    funcC(dp);//基类指针指向基类,此时采用dynamic_cast完成基类到派生类的转换失败。
funcD(dp); return 0; }

运行结果为:

class base*
class derived
class derived
class derived
class base
class base

注意:基类指针或引用指向派生类对象的情况,此时转换才有意义。 否则转换就不能成功,如上面的funcC(dp)函数中derived* dp=dynamic_cast<derived*>(dp)就失败了,返回NULL

 
 

c++中RTTI