本文介绍c++的RTTI的基本用法,并初步研究RTTI的实现原理。

1. 什么是RTTI

RTTI即运行时类型识别(runtime type identification),用于判断指针或引用所绑定对象的动态类型,由两个运算符实现:

  • dynamic_cast  将基类指针或引用安全地转换为派生类的指针或引用
  • typeid  返回表达式的类型

2. 为什么要用RTTI

当我们需要对象的类型信息时,比如需要使用非虚函数,有必要知道当前指针绑定的对象的动态类型。

3. 如何使用RTTI

  • dynamic_cast用于安全的向下转型(type-safe downcast)。需要注意两点:
  • 运算符作用的对象必须含有虚函数。

作用于指针类型时,转换失败返回NULL;作用于引用时,因为引用不能为空,转换失败时返回std::bad_cast异常。

class base{
public:
base(int val):bv(val){}
virtual void printVal(){printf("base::printVal bv=%d\n", bv);}
int bv;
};
class derive:public base{
public:
derive(int val, double d):base(val), dv(d){}
void printVal(){
printf("derive::printVal dv= %f\n", dv);
}
double dv;
}; int main(){
derive d(, 20.00);
base *b = &d;
assert(derive *dp = dynamic<derive*>(b));
return ;

typeid可以作用于任意表达式或类型,当运算对象不属于类类型或不包含虚函数时,返回运算对象的静态类型,否则typeid会直到运行时才决定其动态类型。typeid返回的值是type_info类型对象,type_info::name()返回类型的名字,当然这是编译器相关的。一般用来判断两个对象动态类型是否相同或者某个对象是否是指定类型

printf("%s\n", typeid(derive).name());

6derive

4. 作用原理

那么dynamic_cast和typeid是怎样知道对象的实际类型的,在《inside the c++ object model》中反复提到类型信息是在虚函数表的第一个slot中的,不过这个跟编译器实现出入很大,根据我的上篇文章可以发现gcc实现的虚函数表放的全是虚函数,并没有类型信息。

derive d(, 20.00);
printf("deirve address: %x\n", &d); 

一步步来debug,

derive d(10, 20.00);

(gdb) n

printf("deirve address: %x\n", &d);

(gdb)

deirve address: bffff2a0

(gdb) x /4a 0xbffff2a0

0xbffff2a0:   0x80487e0 <_ZTV6derive+8>   0xa 0x0 0x40340000

d的地址是0xbffff2a0, 第一个是虚函数表指针 0x80487e0,可以发现虚函数表在_ZTV6derive往后8个字节处,_ZTV6derive又是什么?

(gdb) x /16a  0x80487d0

0x80487d0: 0x0 0x40340000 0x0 0x80487fc <_ZTI6derive>

0x80487e0 <_ZTV6derive+8>:  0x80486ca <_ZN6derive8printValEv>  0x0 0x0 0x8048810 <_ZTI4base>

0x80487f0 <_ZTV4base+8>: 0x8048674 <_ZN4base8printValEv> 0x72656436 0x657669   0x804a068 <_ZTVN10__cxxabiv120__si_class_type_infoE@@CXXABI_1.3+8>

0x8048800 <_ZTI6derive+4>:  0x80487f4 <_ZTS6derive>  0x8048810 <_ZTI4base>    0x73616234 0x65

可以发现ZTV6derive处的值为0,后面刚好是一个typeinfo的结构,指向 0x804a068,<_ZTVN10__cxxabiv120__si_class_type_infoE@@CXXABI_1.3+8>很明显是一个class type info的对象。所以gcc在虚函数表前面多加了两个字节,第一个为0,第二个指针指向了一个type info的结构。

至于这个type info结构到底是什么样的,我也没找到资料,希望有知道的同学可以和我交流,谢谢。

c++之RTTI介绍的更多相关文章

  1. C++ RTTI介绍

    一.定义:RTTI:Run Time Type Identification ,执行时类型识别:指程序可以使用基类的指针或引用来检索其所指对象的实际派生类型. 二.使用方式:C++中有两个操作符提供R ...

  2. RTTI

    RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型.   编辑本段RTTI介绍 RTTI提 ...

  3. Delphi 类的类 class of 用法

    http://blog.csdn.net/blue_morning/article/details/8815609 Delphi 类的类 class of 用法   这个概念本来在一个关于Delphi ...

  4. Delphi 类引用 Class Reference 元类 MetaClass 用法

    delphi中类引用的使用实例 类引用类引用(Class Reference)是一种数据类型,有时又称为元类(MetaClass),是类的类型的引用.类引用的定义形式如下: class of type ...

  5. Java系列笔记(2) - Java RTTI和反射机制

    目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这 ...

  6. RTTI (Run-Time Type Identification,通过运行时类型识别) 转

    参考一: RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型.   RTTI提供了以下两个 ...

  7. C++中的RTTI机制解析

    RTTI RTTI概念 RTTI(Run Time Type Identification)即通过运行时类型识别,程序能够使用基类的指针或引用来检查着这些指针或引用所指的对象的实际派生类型. RTTI ...

  8. C++ RTTI

    一.定义:RTTI:Run Time Type Identification ,运行时类型识别:指程序能够使用基类的指针或引用来检索其所指对象的实际派生类型.二.使用方式:C++中有两个操作符提供RT ...

  9. C++重载(主要介绍使用友元函数重载)

    重载限制 多数C++运算符都可以用下面的方式重载.重载的运算符不必是成员函数,但必须至少有一个操作数是用户自定义的类型.下面详细介绍C++对用户定义的运算符重载的限制. 1 重载后的运算符必须至少有一 ...

随机推荐

  1. linux入侵检测系统snort安装配置

    队长让俺瞅瞅snort,没想到安装配置都遇到问题...整理下过程,给跟我一样的家伙看看.. 由于本人机器是ubuntu,apt-get 几下就可以了,其实网上有不少这样的文章...之所以还要写就是.. ...

  2. 慎用preg_replace危险的/e修饰符(一句话后门常用)

    要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误     preg_replace函数原型: mi ...

  3. Linux下校验下载文件的完整性(MD5,SHA1,PGP)

    查看: Linux下校验下载文件的完整性(MD5,SHA1,PGP) http://blog.useasp.net/archive/2014/03/29/use-md5-sha1-or-pgp-to- ...

  4. js中数组操作

    var selectedCodeArray = []; var num = $.inArray(值, selectedCodeArray)  //值在数组中的位置 selectedCodeArray. ...

  5. Asp.Net 之 母版页中对控件ID的处理

    一.问题提出 由于总体排版和设计的需要,我们往往创建母版页来实现整个网站的统一性,最近我由于统一性的需要,把原来整个项目单独的页面全部套用了母版页.但是出现了一系列失效错误. 二. 抽象模型 由于整个 ...

  6. Big String 块状数组(或者说平方分割)

    Big String 给一个字符串,长度不超过 106,有两种操作: 1. 在第 i 个字符的前面添加一个字符 ch 2. 查询第 k 个位置是什么字符 操作的总数不超过 2000 如果直接模拟的话, ...

  7. OC 实现的几个排序算法

    和在VC++6.0里相比 在OC里面实现 不算困难 可是我用惯了C/C++呢 快速排序,冒泡排序,直接插入排序和折半插入排序,希尔排序,堆排序,直接选择排序 /******************** ...

  8. MySQL(26):事务的隔离级别出现问题之 幻读

    1. 幻读 幻读(Phantom Read)又称为虚读,是指在一个事务内两次查询中数据条数不一致,幻读和不重复读有些类型,同样是在两次查询过程中,不同的是,幻读是由于其他事务做了插入记录的操作,导致记 ...

  9. UVa Problem 10132 File Fragmentation (文件还原) 排列组合+暴力

    题目说每个相同文件(01串)都被撕裂成两部分,要求拼凑成原来的样子,如果有多种可能输出一种. 我标题写着排列组合,其实不是什么高深的数学题,只要把最长的那几个和最短的那几个凑一起,然后去用其他几个验证 ...

  10. 在ubuntu 部署svn服务器

    (1)安装svn sudo apt-get install subversion (2)新建一个仓库 mkdir /svn/test chmod 777 /svn/test sudo svnadmin ...