1.我对RTTI的理解
RTTI是一种和虚函数功能类似,但是实现原理不一样的机制。
当我们创建一个类对象,并且使用这个对象时,除了知道这个对象中的成员以外,对于类的信息一概不知,比如这个对象所属类的类名,这个对象的继承关系(子类或者父类是什么等等 ),比如:
Figure *p;
p = new Circle();
Figure &q = *p;
在定义了p这个对象之后,电脑无法通过p本身来获取p所属的类的信息(因为定义这个对象的过程就是分配内存空间和初始化的过程,所有关于类本身的信息不回被存储),比如类名,类的继承关系等。
RTTI就是把这些对象的类信息存储起来而不是丢弃,,最单纯的RTTI存储的类信息有:
●识别(class identification)──包括类名称或ID。
●继承关系(inheritance relationship)──支持执行时期的「往下变换类型」(downward casting)﹐亦即动态变换类型(dynamic casting) 。
扩展的RTTI是:
●对象结构(object layout) ──包括属性的类型、名称及其位置(position或offset)。
●成员函数表(table of functions)──包括函数的类型、名称、及其参数类型等。
其目的是协助对象的I/O 和持久化(persistence) ﹐也提供调试讯息等。
若依照Bjarne Stroustrup 之建议〔注1 〕﹐C++ 还应包括更完整的RTTI﹕
●能得知类所实例化的各对象 。
●能参考到函数的源代码。
●能取得类的有关在线说明(on-line documentation) 。
2.RTTI的用处
RTTI可以替代虚函数
以下面这个程序为例,其中Figure类有两个子类Circle和Rectangle。
使用RTTI版本的程序
void drawing( Figure *p )
{
if( typeid(*p).name() == "Circle" )
((Circle*)p) -> draw();
if( typeid(*p).name() == "Rectangle" )
((Rectangle*)p) -> draw();
}
注意:typeid是C++中的一个操作符,就是RTTI机制的实现,存储了对象所属类的信息,比如typeid(*p).name()就获取了对象的类的名字。
class Figure
{
...
virtual void draw();//定义一个虚函数
...
}
void drawing(Figure *p)
{ p->draw(); }
3.RTTI的底层实现
其实原理很简单,就是在类成员变量中存储类的相关信息,如下所示
class Figure
{ public:
virtual char* Type_na() { return "Figure"; } //存储类名
virtual int Isa(char* cna) { return !strcmp(cna, "Figure")? 1:0; }//检查是否是所需要的类变量
};
4.dynamic_cast
在C++11新特性中,dynamic_cast可以很安全的在具有继承关系的类之间进行转换,因为dynamic_cast就是使用了RTTI机制。