RTTI(Runtime Type Identification)
所谓的RTTI是指在执行的同时判断某个object或某一个pointer属于何种类型,它是C++许多高级技术依领域的基础。RTTI的主要形式在C++中是以typeid和dynamic_cast operator展现。
一、typeid operator
typeid operator 换语法如下:
typeid( type-id) #例如:typeid(CPoint)
typeid(expression) #例如:typeid(pPoint)或typeid(*pPoint)
typeis()可以在程序执行期间决定一个object的类型(type)。它的回传值是一个const type_info&。C++ Standard中对于type_info object定义如下:
class type_info{ public: virtual ~type_info(); bool operator==(const type_info& )const; bool operator!=(const type_info& )const; bool before(const type_info& )const; const char*name()const; //传回class 原始名称 private: //prevent memberwise init and copy type_info(const type_info& ); type_info& operator=(const type_info& ); //data members };
有些文献曾提出以编码后的文字来代替实际的class名称,可能会获得比较好的执行效率。visual C++就是这么做的,在其 \msdev\include\typeinfo.h 中对class type_info 定义如下:
// declared in typeinfo.h class type_info { public: _CRTIMP virtual ~type_info(); _CRTIMP int operator==(const type_info& rhs) const; _CRTIMP int operator!=(const type_info& rhs) const; _CRTIMP int before(const type_info& rhs) const; _CRTIMP const char* name() const; _CRTIMP const char* raw_name() const; private: void *_m_data; char _m_d_name[1]; type_info(const type_info& rhs); type_info& operator=(const type_info& rhs); };
我们可以利用其中的name()和rawname()两个member functions,取出我们所探询之object的类形名称。name()传回的指针,指向一个人类可读的字串,rawname()传回的指针则指向一个编码后的字串,非人类可读形式。此一编码后的字串对于两个类形之间的比对更有效率。
如果你要使用typeid(),程序中必须导入typeinfo.h,下面是个实际的例子:
#include<iostream.h> #include<typeinfo.h> class B //base class ,non-polymorphic { public: int _data1; }; class D :public B //derived class ,non-polymorphic too. { public: int _data2; }; void main() { B *pb = new B; D *pd = new D; cout<<" B is Base type, D is Derived type" <<endl; //check object pointer's type if (typeid(B)==typeid(*pb)) cout<<"pb is B type"<<endl; else cout <<"pb is not B type" <<endl; if (typeid(D)==typeid(*pd)) cout<<"pd is D type"<<endl; else cout <<"pd is not D type" <<endl; //check object pointer's type name cout << "pb's type name = " << typeid(pb).name() << endl; cout << "pd's type name = " << typeid(pd).name() << endl; cout << "pb's type rawname = "<< typeid(pb).raw_name() << endl; cout << "pd's type rawname = "<< typeid(pd).raw_name() << endl; // check object's type name cout << "*pb's type name = " << typeid(*pb).name() << endl; cout << "*pd's type name = " << typeid(*pd).name() << endl; cout << "*pb's type rawname = "<< typeid(*pb).raw_name() << endl; cout << "*pd's type rawname = "<< typeid(*pd).raw_name() << endl; if (typeid(pb).before(typeid(pd))) cout << "pb before pd" << endl; else cout << "pb not before pd" << endl; // check objects' relationship if (typeid(*pb).before(typeid(*pd))) cout << "*pb before *pd" << endl; else cout << "*pb not before *pd" << endl; B *pb1 = new D; // base ptr point to derived object. cout << "pb1's type name = " << typeid(pb1).name() << endl; cout << "*pb1's type name = " << typeid(*pb1).name() << endl; // check objects' relationship if (typeid(*pb1).before(typeid(B))) cout << "*pb1 before B" << endl; else cout << "*pb1 not before B" << endl; if (typeid(*pb1).before(typeid(D))) cout << "*pb1 before D" << endl; else cout << "*pb1 not before D" << endl; }
程序执行结果:
B is Base type, D is Derived type pb is B type pd is D type pb's type name = class B * // 原名称 pd's type name = class D * // 原名称 pb's type rawname = .PAVB@@ // 编码后的名称 pd's type rawname = .PAVD@@ // 编码后的名称 *pb's type name = class B // 原名称 *pd's type name = class D // 原名称 *pb's type rawname = .?AVB@@ // 编码后的名称 *pd's type rawname = .?AVD@@ // 编码后的名称 pb before pd // before 的意思是在 classes hierarchy 的更高层 *pb before *pd pb1's type name = class B * // 合理 *pb1's type name = class B // 想不到吧! *pb1 not before B // 合理 *pb1 before D // 想不到吧!
请注意,虽然pb1指向一个真正的class D object,但利用typeid()所得到的检查结果却显示,pb1所指类的type name 是“class B”,想不到吧!如果我把typeid()应用于polymorphic classes身上,执行结果会出现一点变化,现在将前一个例子做一些修改:
// building : cl -GR typeid.cpp #include <iostream.h> #include <typeinfo.h> class B // base class, polymorphic. { public: virtual void func() { }; int _data1; }; class D : public B // derived class, polymorphic too. { public: virtual void func() { }; int _data2; };
现在让我们看一下执行结果,变化出现在polymorphism发生时,也就是当程序码以base type pointer 指向derived type object时:
B* pb1 = new D; // base ptr point to derived object.
此行之后的执行结果如下:
pb1's type name = class B * // 合理
*pb1's type name = class D // 好极了!
*pb1 not before B // 合理
*pb1 not before D // 合理