15.4.2 RTTI的工作原理(1)
C++(www.cppentry.com)有3个支持RTTI的元素。
如果可能的话,dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针;否则,该运算符返回0-空指针。
typeid运算符返回一个指出对象的类型的值。
type_info结构存储了有关特定类型的信息。
只能将RTTI用于包含虚函数的类层次结构,原因在于只有对于这种类层次结构,才应该将派生对象的地址赋给基类指针。
警告:RTTI只适用于包含虚函数的类。
下面详细介绍RTTI的这3个元素。
1.dynamic_cast运算符
dynamic_cast运算符是最常用的RTTI组件,它不能回答"指针指向的是哪类对象"这样的问题,但能够回答"是否可以安全地将对象的地址赋给特定类型的指针"这样的问题。我们来看一看这意味着什么。假设有下面这样的类层次结构:
接下来假设有下面的指针:
最后,对于下面的类型转换:
哪些是安全的?根据类声明,它们可能全都是安全的,但只有那些指针类型与对象的类型(或对象的直接或间接基类的类型)相同的类型转换才一定是安全的。例如,类型转换#1就是安全的,因为它将Magificent类型的指针指向类型为Magnificent的对象。类型转换#2就是不安全的,因为它将基数对象(Grand)的地址赋给派生类(Magnificent)指针。因此,程序将期望基类对象有派生类的特征,而通常这是不可能的。例如,Magnificent对象可能包含一些Grand对象没有的数据成员。然而,类型转换#3是安全的,因为它将派生对象的地址赋给基类指针。即公有派生确保Magnificent对象同时也是一个Superb对象(直接基类)和一个Grand对象(间接基类)。因此,将它的地址赋给这3种类型的指针都是安全的。虚函数确保了将这3种指针中的任何一种指向Magnificent对象时,都将调用Magnificent方法。
注意,与问题"指针指向的是哪种类型的对象"相比,问题"类型转换是否安全"更通用,也更有用。通常想知道类型的原因在于:知道类型后,就可以知道调用特定的方法是否安全。要调用方法,类型并不一定要完全匹配,而可以是定义了方法的虚拟版本的基类类型。下面的例子说明了这一点。
然而,先来看一下dynamic_cast的语法。该运算符的用法如下,其中pg指向一个对象:
这提出了这样的问题:指针pg的类型是否可被安全地转换为Superb *?如果可以,运算符将返回对象的地址,否则返回一个空指针。
注意:通常,如果指向的对象(*pt)的类型为Type或者是从Type直接或间接派生而来的类型,则下面的表达式将指针pt转换为Type类型的指针: