C++ RTTI

来源:互联网 发布:mac双系统开机怎么切换 编辑:程序博客网 时间:2024/06/05 20:22
一、定义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(工程--设置--C/C++---工程选项)。因为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;}

运行结果:


参考文章:

1.  http://www.cplusplus.com/reference/typeinfo/type_info/
2.  http://en.cppreference.com/w/cpp/language/typeid
3.  http://stackoverflow.com/questions/1986418/typeid-and-typeof-in-c
4.  http://renhl252.blog.163.com/blog/static/2122100720098229281284/

原创粉丝点击