RTTI的用途
得益于虚函数表,如果派生类实现了基类中的虚函数,通过基类指针或引用可以完成正确的函数调用。
但是也不得不考虑另外一种情况:如果某个派生类中实现了基类定义的虚函数以外的函数,此时,只有基类指针或引用,那么该怎样确认其是正确的派生类类型,从而完成派生类独有函数的调用呢?基于这种情形,因此C++提供了RTTI。
RTTI的使用
目前C++支持RTTI元素包括:dynamic_cast和typeid(type_info)。
dynamic_cast
dynamic_cast是最常用的RTTi组件,它解决的是“能否安全的把对象的地址赋给特定类型指针”的问题。我们知道,如果将一个指向派生类的对象赋值给派生类指针或基类指针都是没有问题的,但是如果将基类对象赋值给派生类指针就没有那么安全了,因为基类中并不包含派生类中可能存在的一些独有的数据成员或方法。
通过dynamic_cast,我们可以解决这个问题,示例如下:
class Grand{}
class Superb : public Grand{}
class Magnificent : public Superb{ void say(){} }
Grand *pg = new Grand;
Superb * ps = dynamic_cast<Superb *>(pg);
针对上面的示例而言:如果pg 的类型可被安全地转换为Superb *,那么返回对象地址,否则返回一个空指针。
typeid
typeid可以确定两个对象是否是同种类型,它可以接收两种参数:类名、结果为对象地表达式。
typeid运算符返回一个对type_info对象地引用,type_info重载了 == 和 != 运算符,以便可以使用这些运算符对类型进行比较,示例如下:
typeid(Magnificent) == typeid(*pg)
cout() << typeid(*pg).name(); //返回类型名
如果pg是一个空指针,程序将会引发bad_typeid异常。
使用总结
如下提供了上述两者在实际使用时对比:
Grand *pg ...; //Grand、Superb 、Magnificent 都有可能
Magnificent *pm;
if(pm = dynamic_cast<Magnificent *>(pg))
pm->say();
if(typeid(Magnificent) == typeid(*pg))
pm = (Magnificent *)pg;
pm->say();
从上述代码可以看出,dynamic_cast使用起来比typeid更简洁,所以大多数情况下,我们应当将dynamic_cast作为首选。
dynamic_cast与其他转换运算符
- dynamic_cast:用于类层次结构中的向上转换,这种类型转换是安全的,不允许其他转换。
- const_cast:将const类型转换为非const类型。
- static_cast:当一种类型可被隐式转换为其他类型时,这种转换才是合法的,否则将出错。支持的转换包括向上转换、向下转换、基本类型的转换。
- reinterpret_cast:适用于依赖于实现的底层编程技术,不可移植,用到的情形较少,了解即可。