RTTI的主要内容
RTTI:运行时类型识别。主要有两个运算符实现:
- typeid: 返回对象
- dynamic_cast: 用于将父类的指针或引用安全地转化成子类的指针或引用。
为什么设计RTTI
当处于这种情况时,使用RTTI:当我们想使用基类对象的指针或引用,执行某个派生类的操作,并且该操作不是虚函数时。
一般讲,只要有可能,我们应该尽量使用虚函数。当一个方法被定义成虚函数时,编译器将根据对象的动态类型自动正确地选择正确的方法版本。
但,并不是任何时候都能定义虚函数的。当无法使用虚函数时,就使用RTTI。另一方面,使用RTTI,程序员必须清楚地知道要转换成什么类型,并且检查转换是否成功。
dynamic_cast 使用规则:
- 只能使用对象指针或对象引用的转换:dynamic_cast<bird*>或dynamci_cast<&bird>,而不能是对象本身。
- 需要转换的类型中必须包含虚函数,
- 如果转换成功返回子类地址,否则返回NULL。
typeid 使用规则:
- type_id 返回一个type_info对象的引用。
- 如果想通过基类指针获得派生类的数据类型,基类必须带有虚函数。
- 只能判断当前对象是基类还是子类,无法判断指针是基类还是子类。即typeid()参数是对象,而非指针。
type_info 中的内容:
1 | class type_info{ |
用法与实例
假如由两个类都继承了借口类Flyable:
1 | class Flyable{ |
Bird由飞行能力,且可以觅食,Plane有飞行能力,且可以运输。
可以定义一个函数:
1 | void func(Flyable* obj){ |
1)打印obj
是什么类型。typeid(对象)
:参数是obj
所指向的对象
2)判断当前obj
指针所指向的是什么类型。如果obj
指向的对象是Bird
类型,
3)将原本是Flyable 类型
的obj指针
,cast为Bird 类指针
。并且将转化后的指针复制给一个新的指针。
4)同3)。
此时在main中调用func()。
1 | Bird b ; |
b为Bird类
。
1 | Flyable* plane = new Plane(); |
分别返回Flyable 指针类
,和Plane 类
。
typeid().name()
使用前需要#include <typeinfo>
。
敲黑板在可能的情况下,最好定义虚函数,而非直接管理类型。