RTTI运行时类型识别

type_info

为每一个类型增加一个type_info对象。

 

为了能够在运行时获得对象的类型信息type_info,C++增加了两个运算符:typeid 和 dynamic_cast<>。type_info 常用的三个成员函数是 operator==()、operator!=() 和 name(),请参考标准头文件<typeinfo>.

 

typeid 运算符

它以一个对象或者类型名作为参数,返回一个匹配的const type_info对象,它表明该对象的确切类型.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void  DeviceControllor::ControlThem(HomeElectricDevice& device)
{
     Command cmd = GetCommand();
     
      switch (cmd)
       {
           case  PLAY_CD:
                   if ( typeid (device) ==  typeid (Television))
                   {
                         Television* pTmp =  static_cast <Television*>(&device);
                          pTmp->PlayVCD();
                    }   
       }   
}   

上面代码中:

typeid(device)返回一个type_info对象的引用-该对象持有与device对象相关的必要的运行时信息。

typeid(Television)则返回与类Television相关的类型信息。

当typeid()作用于一个类名而不是一个对象的时候,它总是返回一个对应于该类名的type_info对象。

 

dynamic_cast<>运算符  

typeid()不具备可扩展性,因为它返回一个对象的确切类型而不是基类型。一个派生类对象在语义上也应该是其基类型的对象(如果是public继承),然而typeid()不具备这种判断能力。

dynamic_cast<>能够自动识别对象与类型间is-a的关系。

dynamic_cast<dest_type>(src)

dest_type就是转换的目标类型,而src则是被转换的对象。其行为可以这样描述:如果运行时src和dest_type确实存在is-a关系,则转换可进行;否则转换失败。

  1. dynamic_cast<>可以用来转换指针和引用,但是不能转换对象。
  • 当目标类型是某种类型的指针(包括void*)时,如果转换成功则返回目标类型的指针,否则返回NULL;
  • 当目标类型为某种类型的引用时,如果成功则返回目标类型的引用,否则抛出std::bad_cast异常,因为不存在NULL引用。

      2.  dynamic_cast<>如何能够知道一个基类型指针指向的对象是不是一个派生类对象呢?显然,它一定是通过该对象的vptr检查位于其类型的vtable第一个slot的type_info对象而得知的(见下图),或者不同的编译器对RTTI有不同的实现手段。因此dynamic_cast<>只能用于多态类型对象(拥有虚函数或虚拟继承),否则将导致编译器错误。

 

 

dynamic_cast<>可以实现两个方向的转换:upcast 和 downcast.

  • upcast:把派生类型的指针、引用转换成基类型的指针或引用(实际上这可以隐式地进行,不必显示地转换).
  • downcast:把基类型的指针或引用转换成派生类型的指针或引用。如果这个基类型的指针或引用确实指向一个这种派生类的对象,那么转换就会成功,否则转换就会失败。

 当你使用RTTI时要注意如下事项:

  • 如果你的编译器没有打开RTTI支持,那么请打开它
  • 要想使用RTTI,对象所属类型必须是多态
  • 如果要用dynamic_cast<>转换一个引用,你要保证程序有一条catch()语句来处理std::bad_cast异常
  • 如果试图用typeid来检索NULL指针所指对象的类型信息,将抛出std::bad_typeid异常,像这样:typeid(*p);//p==NULL
  • 当用dynamic_cast<>转换一个指针的时候,要记住检查返回值是否为NULL。

 

最后,来总结一下RTTI背后的实现机制:

      无论基本类型还是用户定义类型,都需要额外的内存来存放type_info对象。

  多态类的type_info对象是如何存放的?要给每一个多态类增加一个指针成员,一个type_info对象,以及给虚函数表增加一项。该方法对任何多态类都是一样的,与程序中对象的个数无关。因此,使用typeid()来检索每个对象运行时的类型信息所花时间是一样的(通过vptr间接完成)。

     同任何其他对象一样,type_info对象的创建过程也需要时间。

     RTTI要求程序维护一颗继承树,dynamic_cast<>能够判断源对象与目标类型之间是否具有is-a关系,这需要在运行时遍历继承树,并且其开销会随着源对象类型与目标类型之间距离(层次)的增大而增大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值