C++ Primer学习笔记——$21 运行时类型识别(RTTI)

题记:本系列学习笔记(C++ Primer学习笔记)主要目的是讨论一些容易被大家忽略或者容易形成错误认识的内容。只适合于有了一定的C++基础的读者(至少学完一本C++教程)。

 
作者: tyc611, 2007-04-07
   本文主要讨论C++的运行时类型识别(RTTI)。
   如果文中有错误或遗漏之处,敬请指出,谢谢!

   本文所述工具RTTI(Run-Time Type Identification)主要用于大型程序,因为该工具的使用需要付出一定的开销。
 
   通过使用RTTI,程序可以在运行时通过基类的指针或者引用来得到所指对象的实际类型。主要有两个操作:(1)typeid操作符:返回指针或者引用所指对象的实际类型。(2)dynamic_cast操作符:将基类类型的指针或引用安全地转换为派生类型的指针或者引用。注意:只有当类中至少有一个虚函数时,才能返回我们所需的动态类型信息;否则,只能返回静态类型信息。
 
dynamic_cast操作符
 
   当dynamic_cast用于基类指针时,该指针必须是有效的——要么是0,要么是指向一个对象。如果绑定到引用或指针的对象不是目标类型的对象,则dynamic_cast失败。如果转换到指针类型的dynamic_cast失败,则dynamic_cast的结果是0值;如果转换到引用类型的dynamic_cast失败,则抛出一个bad_cast类型的异常。因此,dynamic_cast操作符一次执行两个操作:首先验证被请求的转换是否有效,只有当转换有效时才进行实际转换。例如:
   Base *pB;
   // ...
   if (Derived *pD = dynamic_cast<Derived*>(pB) {
      // use the Derived object by pD
   } else {
      // use the Base object by pB
   }
   Base &b = oneObj;
   try {
      Derived &d = dynamic_cast<Derived&>(b);
      // use the Derived object to which b referred
   } catch (bad_cast) {
      // not Derived object
   } 
 
typeid操作符
 
   typeid表达式形如:
      typeid(expr);
这里expr是任意表达式或者类型名。如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。
 
   typeid操作符的返回结果是名为type_info的标准库类型的对象的引用(在头文件typeinfo中定义)。标准并没有确切定义type_info,它的确切定义编译器相关的,但是标准却规定了其实现必需提供如下四种操作:
 t1 == t2 如果两个对象t1和t2类型相同,则返回true;否则返回false
 t1 != t2 如果两个对象t1和t2类型不同,则返回true;否则返回false
 t.name() 返回类型的C-style字符串,类型名字用系统相关的方法产生
 t1.before(t2) 返回指出t1是否出现在t2之前的bool值
type_info类提供了public虚析构函数,以使用户能够用其作为基类。它的默认构造函数和拷贝构造函数及赋值操作符都定义为private,所以不能定义或复制type_info类型的对象。程序中创建type_info对象的唯一方法是使用typeid操作符(由此可见,如果把typeid看作函数的话,其应该是type_info的友元)。type_info的name成员函数返回C-style的字符串,用来表示相应的类型名,但务必注意这个返回的类型名与程序中使用的相应类型名并不一定一致(往往如此,见后面的程序),这是由实现所决定的,标准只要求实现为每个类型返回唯一的字符串。例如:

#include <iostream>

using namespace std;

class Base {};
class Derived: public Base {};

int main()
{
    cout << typeid(int).name() << endl
         << typeid(unsigned).name() << endl
         << typeid(long).name() << endl
         << typeid(unsigned long).name() << endl
         << typeid(char).name() << endl
         << typeid(unsigned char).name() << endl
         << typeid(float).name() << endl
         << typeid(double).name() << endl
         << typeid(string).name() << endl
         << typeid(Base).name() << endl
         << typeid(Derived).name() << endl
         << typeid(type_info).name() << endl;
         
    return 0;
}

在MinGW2.05下的运行结果:
i
j
l
m
c
h
f
d
Ss
4Base
7Derived
St9type_info


Terminated with return code 0
Press any key to continue ...

 
   注意:当把typeid作用于指针的解引用*p时,若指针p为0,则:如果p指向的类型是带虚函数的类类型,则typeid(*p)在运行时抛出一个bad_typeid异常;否则,typeid(*p)的结果与p的值是不相关的,在编译时就可以确定。typeid表达式的这点性质与sizeof表达式相似但又有区别,sizeof一定是在编译时进行计算,也就是说,其只考虑表达式的静态类型,与表达式的动态类型无关(即使有虚函数存在)。
 

参考文献:
[1] C++ Primer(Edition 4)
[2] Thinking in C++(Edition 2)
[3] International Standard:ISO/IEC 14882:1998
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值