【C/C++学习】之十四、RTTI
RTTI(Runtime TypeIdentification)
提供了运行时确定对象类型及转换指针或引用类型的方法。 有关内容包括类名称,数据成员名称与类型,函数名与类型等。
在大多数面向度地向专家传播自己设计理念时,都主张在设计和开发中使用虚拟成员函数而不是使用RTTI机制,但是再很多情况下虚拟成员函数无法克服本身的局限。每当涉及处理异类容器和根基类层次时,不可避免要对对象类型进行动态判断,也就是动态类型的侦测。在C++中提供了两个运算符typeid 和 dynamic_cast。
typeid 可以获取与某个对象关联的运行时类型信息。他返回的是type_info类型,该类型描述类型信息。
Typeid运算符用于获得一个类型或者对象的运行时信息,如下:
Typeid(type)
Typeid(object)
其中type可以是有虚函数的类类型,也可以是没有虚函数的类类型
1、 有虚函数
A *a = new B;
Typeid(a)==typeid(A*);和typeid(*a)==typeid(A) 都返回true
2、 无虚函数
A *a = new B;
Typeid(a)==typeid(A*)和typeid(*a)==typeid(A)都返回true
Typeid是在typeinfo.h头文件中,看下面代码
A *a = new B;
Cout << typeid(*a).name() <<endl;
Name函数可以获得指针a指向的对象类型,因为指针a指向的是一个B类型的对象,多以执行的时候会输出B。
如果a是NULL,那么会抛出bad_typeid异常。
Typeid和dynamic_cast区别:
1、 dynamic_cast运算符只能处理对象,而typeid运算符能够以类型和对象作为操作数,其中对象可以使基本类型,包括整形,浮点型,char等
2、 typeid()和dynamic_cast<>()函数都是在运行时才能获得类型信息,而不是在静态编译时获得。
3、 typeid()函数不是一个模板函数
4、 typeid()和dynamic_cast<>()函数接收基类指针或者引用,该指针或者引用可以指向一个派生类对象。
5、 typeid()函数返回类名,而dynamic_cast<>()函数被用来传递类名。
6、 使用typeid()函数能发现该对象的精确类型,但不能转换该指针,dynamic_cast<>()函数能转换该指针,但不能确定该对象的精确类型。
Dynamic_cast
执行dynamic_cast运算符需要额外的运行时间,为了避免性能损耗通常使用static_cast运算符。 虽然使用static_cast运算符在速度上优于dynamic_cast运算符,但是static_cast运算符在用于向下转型时可能存在危险并会导致错误。 如果一定要使用static_cast运算符,那么就要确保向下转型的安全性。
使用static_cast运算符并不能保证转型的有效性,static_cast运算符仅仅执行需要的指针运算,为了确保使用static_cast运算符进行向下转型是安全的,用户必须对每次要执行的转型都进行测试。如果使用dynamic_cast运算符就无需用户测试,因为dynamic_cast运算符执行失败时会返回空指针或抛出异常。
要注意的是:
默认情况下,编译器是关闭RTTI的,目的是消除性能上的开销,如果程序中使用了RTTI,那么编译前要进行启用RTTI。
最基本的RTTI包括:
1、 类识别:类名称或ID
2、 继承关系:支持运行时的向下转换,即动态转换
3、 对象结构:属性的类型、名称及其位置
4、 成员函数:函数的类型、名称及其参数类型等
5、 能获得类所实例化的各对象
RTTI常见的应用: 异常处理,动态转换,多个文件集成,对象IO
1、 异常处理:需要RTTI 例如类名称等
2、 动态转换:在类中,向下转换需要类继承的RTTI
3、 多个文件集成:当某个程序中的对象需要使用另一个程序中的对象时,在一般的C++程序中,常见的解决方法是在源代码中将需要的对象的类定义包含进来,在编译时将当前文件与其包含的文件集成,但又无法再次重新编译,因此只能依赖于RTTI。
4、 对象IO:C++将IO对象及与它相关的独享所属的类名称等RTTI内容完整的保存起来,读取对象时可依赖这些RTTI内容为对象分配内存空间。
2012/10/14
jofranks 于南昌