运行时类型识别RTTI(Run Time Type Identification)
使用场景:当我们用父类指针或引用执行派生类的操作,并且该操作不是虚函数,则可以使用RTTI。(一般我们会将其声明为虚函数,调用时,系统会根据对象动态类型来确定具体函数的调用)
注:使用RTTI风险极大,一般使用虚函数而不是直接管理对象类型。
RTTI实现,一般使用以下两个运算符实现:
1、typeid:用以返回表达式/对象的类型。
2、dynamic_cast:用于将基类的指针或引用安全地转换为子类的指针或引用。
一、dynamic_cast运算符
使用形式
type的类型必须是一个类类型,并且通常应该含有虚函数
dynamic_cast<type*> (e) //e必须是一个有效地指针
dynamic_cast<type&> (e) //e必须是一个左值
dynamic_cast<type&&> (e) //e不能是一个左值
e的类型必须是type类型的公有基类/公有派生类/type类自身中的一个
如果符合上述条件,则转换成功,否则失败。如果e是指针类型,失败时返回0,
如果是e是引用类型,失败则抛出一个bad_cast异常。
指针类型的dynamic_cast,
//假设A类是一个基类,并且至少含有一个虚函数,B是A的一个
//公有派生类, A* a = new A;
if(B* b = dynamic_cast<B*> (a))
{
使用b指向的B类型对象
}
else
{
a指向一个A对象,使用a指向的A对象
}
引用类型的dynamic_cast,
void function(const A &a)
{
try
{
const B &b = dynamic_cast<const B&> (a);
使用a引用的B对象
}
catch(bad_cast)
{
处理类型转换失败的情况
}
}
二、typeid运算符
使用形式:
typeid(e);
返回e的类型,结果是一个常量对象的引用
e可以是任意表达式或者类型的名字,e是引用时,返回的是所引对象的类型,e是
函数或者指针时,不会执行指针类型标准转换,例如对数组e执行:
typeid(e);
所得结果为数组类型而不是指针类型。
结果的类型是标准库类型type_info或者type_info的公有派生类
注意:当e不是类类型或者类中不包含虚函数,typeid指示的是运算对象的
静态类型,当e中至少定义了一个虚函数的左值时,操作的结果则在运行时才
确定。
typeid使用情形:
(1):两个对象的类型是否相同
(2):一个对象的类型与指定类型是否相同
//B公有继承A
B *b = new B;
A *a = b;
if(typeid(*a) == typeid(*b)){...} //a 和 b指向同一类型的对象
if(typeid(*a) == typeid(B)){...} //运行时判断对象类型是否与指定类型相同
注意:当typeid作用于指针(而非指针指向的对象)时,返回的是该指针静态编译时类型。