RTTI是Runtime Type Identification的缩写,意思是运行时类型识别。C++引入这个机制是为了让程序在运行时能根据基类的指针或引用来获得该指针或引用所指的对象的实际类型。但是现在RTTI的类型识别已经不限于此了,它还能通过typeid操作符识别出所有的基本类型(int,指针等)的变量对应的类型。
C++通过以下的两个操作提供RTTI:
(1)typeid运算符,该运算符返回其表达式或类型名的实际类型。
(2)dynamic_cast运算符,该运算符将基类的指针或引用安全地转换为派生类类型的指针或引用。
下面分别详细地说明这两个操作的实现方式。
注所有的测试代码的测试环境均为:32位Ubuntu 14.04 g++ 4.8.2,若在不同的环境中进行测试,结果可能有不同。
1、typeid运算符
typeid运算符,后接一个类型名或一个表达式,该运算符返回一个类型为std::tpeinf的对象的const引用。type_info是std中的一个类,它用于记录与类型相关的信息。类type_info的定义大概如下:
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;
private:
type_info(const type_info&);
type_info& operator=(const type_info&);
// data members
};
至于data members部分,不同的编译器会有所不同,但是都必须提供最小量的信息是class的真实名称和在type_info对象之间的某些排序算法(通过before()成员函数提供),以及某些形式的描述器,用来表示显式的类的类型和该类的任何子类型。
从上面的定义也可以看到,type_info提供了两个对象的相等比较操作,但是用户并不能自己定义一个type_info的对象,而只能通过typeid运算符返回一个对象的const引用来使用type_info的对象。因为其只声明了一个构造函数(复制构造函数)且为private,所以编译器不会合成任何的构造函数,而且赋值操作运行符也为private。这两个操作就完全禁止了用户对type_info对象的定义和复制操作,用户只能通过指向type_info的对象的指针或引用来使用该类。
下面说说,typeid对静态类型的表达式和动态类型的表达式的处理和实现。
1)typeid识别静态类型
当typeid中的操作数是如下情况之一时,typeid运算符指出操作数的静态类型,即编译时的类型。
(1)类型名
(2)一个基本类型的变量
(3)一个具体的对象
(4)一个指向不含有virtual函数的类对象的指针的解引用
(5)一个指向不含有virtual函数的类对象的引用