RTTI(Runtime Type Identification),译为运行阶段类型识别。是新添加到C++的特性。
1、用途。
对于一个类层次结构:其中的类都是从一个基类派生而来,则可以让基类指针指向其中任何一个类的对象。
则可以调用函数:在处理一些信息后,选择一个类,并创建这种类型的对象,之后返回它的地址。
该地址可以被基类指针引用。然而,我们并不知道基类指针指向的是什么对象。
在回答这个问题前,先考虑为何要知道类型——若仅仅是希望调用类方法的正确版本,则只要该类层次结构中所有成员都拥有虚函数,则并不需要知道真正的类型。
而相反,派生对象也可能包含不是继承而来的方法,在这种情况下,只有某些类型的对象可以使用该方法——无论是出于调试或是向跟踪生成的对象的类型。对于后两种,RTTI提供解决方法。
2、工作原理。
C++有三个支持RTTI的元素。
1、如果可能的话,dynamic_cast 将使用一个指向基类的指针来生成一个指向派生类的指针,否则将返回0。
2、typeid运算符返回一个指出对象的类型的值。
3、type_info结构存储了有关特定类型的信息。
详细介绍:
1、dynamic_cast:
它是最常见的RTTI组件,它回答“是否可以安全地将对象的地址赋给特定类型的指针”的问题。
使用如下:
class Grand{};
class Superb: public Grand{};
class Magnificent:public Superb{};
dynamic_cast<Type *>(pt);
Super * pm = dynamic_cast<Superb *>(bg);
其中,若pt指针指向的类型为Type或从Type派生而来的类型,则dynamic_cast将pt的类型转换为Type* 类型的指针,否则结果为0,返回空指针。
2、typeid运算符和type_info类
typeid运算符使得能够确定两个对象是否为同种类型,于sizeof相似,不过能接受两种参数。
1、类名;2、结果为对象的表达式。
同时,typeid返回一个对type_info对象的引用,type_info是在头文件typeinfo中定义的一个类,它重载了==和!=运算符,以便可以用这些运算符对类型进行比较。
typeid(Magnificent) == typeid(*pg)
其中,若pg指向一个空指针,将引发bad_typeid异常——它在typeinfo声明,由exception派生。
同时,type_info类的实现随厂商而异,但包含一个name()成员——它可以显示类名。
类型转换运算符
比起C语言的强制转换,C++采取了更为严格地限制转换的措施,并添加了4个类型转换运算符。
1、dynamic_cast;
2、const_cast;
3、static_cast;
4、reinterpret_cast;
dynamic_cast已在上文提到——它实现类层次结构的向上转换。语法为:
dynamic_cast<type_name>(expression)
const_cast运算符用于执行只有一种用途的类型的转换。即改变值为const或volatile,语法与dynamic_cast相同。
注意其中的volatile:volatile是一个特征修饰符(type specifier).volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
High bar;
const High * pbar = &bar;
High * pb = const_cast<High *>(pbar);
const Low * pl = const_cast<const Low*>(pbar); //invalid
在上述的代码中,第一条尝试将const High* 类型转换为High *类型,这样就能通过pb指针修改它的值。
而第二条语句却尝试将const High * 转换为const Low *,不符合要求。
3、static_cast
在
static_cast<type_name>(expression)
中,它仅允许能从type_name到expreesion所属类型或从expression所属类型到type_name的隐式转换。
例:若A类由B类派生,则A、B类可相互转换,而与之无关的C类则不能转换。
4、reinterpret_cast运算符用于天生危险的类型转换——它不允许删除const,但会执行其他操作。
语法:
reinterpret_cast<type_name>(expression)
使用如下:
struct dat{short a;short b};
long value = 0xA224B118;
dat*pt = reinterpret_cast<dat*>(&value);
cout<<hex<<pd->a;
long类型拥有的字节数为32,地址与两个short相当,因此转换成立。它将0xA224B118的值在底层转换为了两个int类型。
要注意,它也不能执行所有的类型转换,如将指针类型转换为更小的整型或浮点数。也不能完成函数指针与数据指针的转换。