翻看C++的书,对RTTI的讲解都很困惑,"你知道你的对象是哪个类吗?","RTTI常用于调试和数据库程序"对这些讲解本来就对"运行时类型识别"这个词很迷惑的我来说就更迷糊了.我认为还是C++ PRIMER这本书讲的很好.一开始就给出了答案:RTTI允许"用指向基类或引用来操纵对象"的程序能够获取到"这些指针所指对象"的实际派生类型.这句话虽然很苦涩难懂,但讲的再清楚不过了.RTTI就是对多态的类型转换的反操作,我讲的可能不是很标准.没有人家的讲的话那么严谨,呵呵.对RTTI基本使用dynamic_cast 和 typeid两种操作方式.
第一:dynamic_cast操作.无论怎么看书我对这个操作都很迷茫,越看越觉得有点懂还有点不懂.后来我仔细的思考后感觉dynamic_cast使用必须满足一个条件,就是所操纵的对象必须有一个虚函数.我知道C++中的对象实际上就是指向内存中的一些变量,而虚函数就是变量多一个函数指针.这样就得到答案:dynamic_cast实际上就是判断两个对象的虚函数指针是不是指向同一个函数地址.那么dynamic_cast就是一种强制类型转换操作,它提供一种安全的工作方式,可以将父类转换成子类.
dynamic_cast有指针判断和引用判断两种,下面用C++ PRIMER上的例子进行举例:
class employee{ public: virtual int salary(); }; class programmer:public employee{ public: int salary(); int bonus(); }; //使用指针 void company::payroll(employee *pe){ if (programmer *pm=dynamic_cast<programmer*>(pe)) { pm->bonus(); } } //使用引用 void company::payroll(employee &re){ try { programmer &rm=dynamic_cast<programmer &>(re); rm.bonus(); } catch (std::bad_cast) { } }
第二:typeid操作.对typeid的理解好象容易的多,它返回type_info这个类,根据书上的讲解,type_info这个类是编译器实现的,这个类根据不同的编译器会有不同的支持,包括比较两个对象,对象的类名,还会有函数清单,类型对象的内存布局等.那比较两个对象就可以用这个类实现更强大的功能.对于type_info这个类的使用我有很多疑问,它是跟类一起创建的?还是跟对象一起创建的?如果保存对象是不是也要保存thpe_info这个类对象呢?可是这些书上都没有答案。毕竟这是一本初级的书,可能需要到高级或实际编程中获得答案。type_info的构造函数是私有的,这个类必须由typeid才创建,那就说明typeid是type_info类的一个友元.但让我非常迷惑的是typeid写法.还是以C++ PRIMER上的例子的来说明.
#include <typeinfo> employee *pe =new manager; employee re=*pe; //这里为什么不能用在RTTI呢? if(typeid(pe)==typeid(employee*))//true if(typeid(pe)==typeid(manager*))//false if(typeid(pe)==typeid(employee))//false if(typeid(pe)==typeid(manager))//false //这个还好理解吧 if(typeid(*pe)==typeid(manager))//true if(typeid(*pe)==typeid(employee))//false //这个也可以 if(typeid(re)==typeid(manager))//true if(typeid(re)==typeid(employee))//false //这里又不行了. if(typeid(&re)==typeid(employee*))//true if (typeid(&re)==typeid(manager*))//false
我对这样的写法很难理解,到底哪个写法是正确的呢?经过我仔细的阅读才明白原来typeid不但可以用在RTTI上.还可以用在识别各种类,变量和常量上.用于识别它们的数据类型.比如C++ PRIMER上的例子:
int i; cout<<typeid(i).name()<<endl;//打印:int cout<<typeid(8.16).name()<<endl;//打印:double class Bass{/*没有虚函数*/}; class Derived :public Bass{/*没有虚函数*/}; Derived dobj; Bass *pb=&dobj; cout<<typeid(*pb).name()<<endl;//打印:Base
那么怎么写才可以用在RTTI的类型转换上呢?那就是表达式是一个类的类型.而不是一个类的指针.
上面对RTTI的学习笔记都写完了,也可能有理解错误的地方,在这里记录一下.方便今后使用的时候来阅读.