RTTI全称是RunTime Type Identification,即运行时类型识别,这是C++的一个新特性。程序能够使用基类类型指针或引用来检索这些指针或引用在运行时所指对象的实际的类型:派生类或者基类。
通过两个操作符来提供RTTI:
(1)typeid操作符,返回指针或者引用的实际类型;
(2)dynamic_cast操作符,将基类类型指针或者引用安全的转换位派生类类型的指针或者引用。
1. typeid操作符
该操作符的使用形如:typeid(e),其中e是任意表达式或者类型名。
如果表达式的类型是类类型且这个类中包含一个或者多个虚函数,则表达式的动态类型可能不同于它的静态类型;如果表达式的类型是内置类型或者是类类型但是没有包含任何虚函数,则表达式的动态类型和静态类型一致。例如,如果表达式是基类类型引用或者是对基类指针解引用,则表达式的静态编译时类型是基类型,但如果指针或引用实际指向派生类对象,则typeid就会告诉我们表达式的类型是派生类类型。
typeid操作符的结果是名为type_info的标准库类型的对象引用。要使用这个类,必须include头文件typeinfo。type_info这个类的默认构造函数、复制构造函数以及赋值操作符都定义成了private,所以不能定义或者复制type_info类型对象,只能通过typeid操作符来创建type_info类对象。这个类里有一个函数是经常用的name(),它返回C风格字符串,是类型名字的可显示版本。
常见用途如下:
derived *pd=new derived;
base *pb=pd;
//比较两个表达式的类型
if (typeid(*pb) == typeid(*pd))
{
//do something
}
//比较表达式类型和特定类型
if (typeid(*pb) == typeid(derived))
{
//do something
}
注意:只有当typeid的操作数是带虚函数的类类型的对象的时候,才返回动态类型信息。测试指针只返回指针的静态类型。
所以,如下测试用用于是失败的:
if (typeid(pb) == typeid(derived))
{
//do something
}
2. dynamic_cast操作符
它实际上是C++中4中强制类型转换操作符之一,但是dynamic_cast涉及运行时类型检查,所以它能安全的将基类类型对象的引用或指针转换为同一继承层次中其他类型的引用或者指针。和typeid操作符有点不同,dynamic_cast待转换的基类类型中必须包含一个或者多个虚函数,否则不能使用dynamic_cast操作符(编译都通过不了)。
转换指针方式如下:
derived * pd = dynamic_cast<derived*>(pb);
在运行时检查,如果pb指向继承类对象,那么转换成功;如果pb 指向基类对象,那么转换的结果是0,即pd为0。
转换引用方式如下:
derived & rd=dynamic_cast<derived&>(rb);
当rb实际引用的是一个基类对象,则转换失败,抛出一个std::bad_cast异常;当rb实际引用的是一个继承类对象,则转换成功。
在实际的应用中,当我们不能修改基类,但能在继承类中增加函数,此时我们无法使用虚函数来调用继承类的新增函数,但是可以使用dynamic_cast来将基类指针或者引用安全的转换为继承类指针或者引用,这样就可以访问新增的函数。