一、定义:RTTI:Run Time Type Identification ,执行时类型识别:指程序可以使用基类的指针或引用来检索其所指对象的实际派生类型。
二、使用方式:C++中有两个操作符提供RTTI:
(1)typeid 操作符:返回指针或引用所指对象的实际类型。
(2)dynamic_cast 操作符:将基类类型的指针或引用安全地转换为派生类型的指针和引用。
注:此二操作符仅仅为带有一个或多个虚函数的类返回动态类型信息----即在执行时执行RTTI操作符;对于其它类型则返回静态类型的信息---即在编译时计算RTTI操作符。
三、详细介绍:
(1)typeid
头文件:# include<typeinfo>
语法--两种形式:typeid (type) 、typeid (expression)即随意表达式或类型名。 常见的用途:比較两个表达式的类型。或者将表达式的类型与特定类型相比較。
typeid返回类型:const type_info&;
详细定义例如以下:
- class type_info{
- public:
- virtul ~type_info();
- bool operator == (const type_info&rhs)const;
- bool operator != (const type_info&rhs)const;
- bool before(const type_info&rhs)const;
- const char* name()const;
- private:
- type_info(const type_info& rhs);
- type_info& operator=(const type_info& rhs);
- }
接口说明:
operator ==和operator!=:比較操作符。返回两个类型是否为(或不为)同一类型(注:基类和派生类不为同一类型! )。
before:若在类型排序中。该类型先于rhs的类型则返回true。 name:返回类型相应的名字(详细所用的值,依赖于详细编译器)(以\0结束的字符串)。
注意:type_info类的默认构造函数和复制构造函数以及赋值操作符都定义为private,故不能定义或复制type_info类型的对象。程序中创建type_info对象的唯一方法是使用typeid操作符。 样例:(来源)
- #include <iostream>
- #include <typeinfo>
- using namespace std;
- struct Base {};
- struct Derived : Base {};
- struct Poly_Base {virtual void Member(){}};
- struct Poly_Derived: Poly_Base {};
- int main() {
- int a;
- int * pa;
- cout << "int is: " << typeid(int).name() << endl;
- cout << " a is: " << typeid(a).name() << endl;
- cout << " pa is: " << typeid(pa).name() << endl;
- cout << "*pa is: " << typeid(*pa).name() << endl << endl;
- Derived derived;
- Base* pbase = &derived;
- cout << "derived is: " << typeid(derived).name() << endl;
- cout << "*pbase is: " << typeid(*pbase).name() << endl;
- cout << "same type? ";
- cout << ( typeid(derived)==typeid(*pbase) ) << endl << endl;
- Poly_Derived polyderived;
- Poly_Base* ppolybase = &polyderived;
- cout << "polyderived is: " << typeid(polyderived).name() << endl;
- cout << "*ppolybase is: " << typeid(*ppolybase).name() << endl;
- cout << "same type? ";
- cout << ( typeid(polyderived)==typeid(*ppolybase) ) << endl << endl;
- return 0;
- }
执行结果:(尝试了两个编译环境:g++ (GCC) 4.4.6 20120305 (Red Hat 4.4.6-4) 和 VC6.0)
G++结果:
VC6.0结果:
注:尽管 typeid(*ppolybase)返回派生类类型。可是 typeid(ppolybase)依然是返回基类指针类型。 同理,引用相似:假设r是引用,typeid(r)返回派生类类型,typeid(&r)则依然返回基类类型。
注意到:两个编译环境的执行结果不一样---即typeid在不同编译环境下返回的结果是不一致的! 为什么会这样呢?
由于:标准C++规定,type_info类的确切定义随编译器而变化,仅仅要保证全部的实现提供以上的基本操作即可(见类定义)。即详细实现细节。各编译器厂商可自行决定。
注:在VC6.0执行时,记得把编译选项加上“/GR“ ,否则编译时会出现Warning(project--设置--C/C++---project选项)。 由于VC6.0默认不开启RTTI。 (2)dynamic_cast
语法形式:dynamic_cast<T>(v) ,将对象 v 转换为类型T的对象。
前提:v 要么为指向其派生类对象的基类指针,要么为引用其派生类对象的基类对象。否则。v 返回NULL(为指针时)或抛出std::bad_cast(在头文件<typeinfo>中定义)异常(为引用类型时);而T为所期望的派生类指针类型或派生类引用类型。 且。v指向的基类里必须包括虚函数,即多态类型。否则编译出错。 经常使用写法:
I、Poly_Derived* derivedPtr = dynamic_cast<Poly_Derived*>(ppolybase);//转换为指向Poly_Derived 型的指针,失败返回NULL;
II、Poly_Derived& derivedRef = dynamic_cast<Poly_Derived&>(polyderived); //转换为Poly_Derived 引用,失败时抛出bad_cast异常。
详细见样例:
- #include <iostream>
- #include <typeinfo>
- using namespace std;
- struct Poly_Base {virtual void Member(){}};
- struct Poly_Derived: Poly_Base {};
- int main() {
- Poly_Derived polyderived;
- Poly_Base* ppolybase = &polyderived;
- Poly_Base& rpolybase = polyderived;
- if(Poly_Derived* derivedPtr = dynamic_cast<Poly_Derived*>(ppolybase))//base pointer
- {
- cout<<"dynamic_cast pointer success."<<endl;
- }
- else
- {
- cout<<"dynamic_cast pointer fail!"<<endl;
- }
- try{
- const Poly_Derived& derivedRef = dynamic_cast<const Poly_Derived&>(rpolybase);
- cout<<"dynamic_cast reference success."<<endl;
- }catch(bad_cast){
- cout<<"dynamic_cast reference fail."<<endl;
- }
- cout <<"same type? ";
- cout << ( typeid(rpolybase)==typeid(*ppolybase) ) << endl;
- return 0;
- }
执行结果:
原文链接: http://blog.****.net/heyabo/article/details/8348624
參考文章:
1. http://www.cplusplus.com/reference/typeinfo/type_info/
2. http://en.cppreference.com/w/cpp/language/typeid
3. http://*.com/questions/1986418/typeid-and-typeof-in-c
4. http://renhl252.blog.163.com/blog/static/2122100720098229281284/