RTTI(Run-Time Type Identification 运行时类型识别)是面向对象程序设计中一种重要的技术。
和很多其他语言一样,C++是一种静态类型语言。其数据类型是在编译期就确定的,不能在运行时更改。然而由于面向对象程序设计中多态性的要求,C++中的指针或引用(Reference)本身的类型,可能与它实际代表(指向或引用)的类型并不一致(比如基类指针指向派生类对象)。有时我们需要将一个多态指针转换为其实际指向对象的类型,就需要知道运行时的类型信息,这就产生了RTTI的要求。
C++提供了两个关键字typeid和dynamic_cast和一个type_info类来支持RTTI.
dynamic_cast操作符
它允许在运行时刻进行类型转换,从而使程序能够在一个类层次结构安全地转换类型(主要是安全向下转型)。dynamic_cast提供了两种转换方式,把基类指针(或引用)转换成派生类指针(或引用)。如:
class BaseClass
{
public:
virtual ~BaseClass(){}
virtual void dispaly(){}
};
class DerivedClass : public BaseClass
{
public:
virtual ~DerivedClass(){}
virtual void dispaly(){}
};
DerivedClass obj;
BaseClass* pB = &obj;
DerivedClass* pD = dynamic_cast<DerivedClass*>(pB);
typeid操作符
指出指针或引用指向的对象的实际类型。typeid可以用于作用于各种类型名,对象和内置基本数据类型的实例、指针或者引用,当作用于指针和引用将返回它实际指向对象的类型信息。typeid操作符的返回结果是名为type_info的标准库类型的对象的引用。
type_info类:这个类的确切定义是与编译器实现相关的,在头文件typeinfo中定义。
typeid(typename); //typename为类型名,如int
typeid(expr); //expr为表达式,如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。
type_info的默认构造函数和拷贝构造函数及赋值操作符都定义为private,所以不能定义或复制type_info类型的对象。程序中创建type_info对象的唯一方法是使用typeid操作符.type_info的name成员函数返回C-style的字符串,用来表示相应的类型名,但务必注意这个返回的类型名与程序中使用的相应类型名并不一定一致,具体由编译器的实现所决定,标准只要求实现为每个类型返回唯一的字符串。
例如,在Codeblocks 8.02上试验,结果如下:
BaseClass bObj, *pb=NULL;
DerivedClass dObj;
cout<< typeid(bool).name() << endl
<< typeid(char).name() << endl
<< typeid(unsigned char).name() << endl
<< typeid(short).name() << endl
<< typeid(unsigned short).name() << endl
<< typeid(int).name() << endl
<< typeid(unsigned int).name() << endl
<< typeid(long).name() << endl
<< typeid(unsigned long).name() << endl
<< typeid(long long).name() << endl
<< typeid(float).name() << endl
<< typeid(double).name() << endl
<< typeid(void).name() << endl
<< typeid(void*).name() << endl
<< typeid(string).name() << endl
<< typeid(BaseClass).name() << endl
<< typeid(DerivedClass).name() << endl
<< typeid(bObj).name()<<endl
<< typeid(pb).name()<<endl
<< typeid(dObj).name()<<endl;
大致规律是:
1.内置类型一般先是第一个字母
2.相应的Unsigned的内置类型是其第一个字母的后一个字母,如unsigned int是j
3.内置类型指针是在其第一个字母前加一个p,如void*是Pv
4.C++的类类型是显示其名称
5.用户自定义类型是表示名称字母个数的数字加上完整的名称
如果typeid操作符的操作数是至少包含一个虚拟函数的类类型时,并且该表达式是一个基类的应用,则typeid操作符指出底层实际对象的派生类类型。
DerivedClass dObj;
BaseClass *pb = dynamic_cast<BaseClass*>(new DerivedClass);
BaseClass &rb = dObj;
DerivedClass *pd = &dObj;
DerivedClass *pd1 = dynamic_cast<DerivedClass*>(pb);
cout << typeid(pb).name() <<endl
<< typeid(*pb).name()<<endl
<< typeid(rb).name()<<endl
<< typeid(pd).name()<<endl
<< typeid(*pd1).name()<<endl;