c++之RTTI介绍
本文介绍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介绍的更多相关文章
- C++ RTTI介绍
一.定义:RTTI:Run Time Type Identification ,执行时类型识别:指程序可以使用基类的指针或引用来检索其所指对象的实际派生类型. 二.使用方式:C++中有两个操作符提供R ...
- RTTI
RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型. 编辑本段RTTI介绍 RTTI提 ...
- Delphi 类的类 class of 用法
http://blog.csdn.net/blue_morning/article/details/8815609 Delphi 类的类 class of 用法 这个概念本来在一个关于Delphi ...
- Delphi 类引用 Class Reference 元类 MetaClass 用法
delphi中类引用的使用实例 类引用类引用(Class Reference)是一种数据类型,有时又称为元类(MetaClass),是类的类型的引用.类引用的定义形式如下: class of type ...
- Java系列笔记(2) - Java RTTI和反射机制
目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这 ...
- RTTI (Run-Time Type Identification,通过运行时类型识别) 转
参考一: RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型. RTTI提供了以下两个 ...
- C++中的RTTI机制解析
RTTI RTTI概念 RTTI(Run Time Type Identification)即通过运行时类型识别,程序能够使用基类的指针或引用来检查着这些指针或引用所指的对象的实际派生类型. RTTI ...
- C++ RTTI
一.定义:RTTI:Run Time Type Identification ,运行时类型识别:指程序能够使用基类的指针或引用来检索其所指对象的实际派生类型.二.使用方式:C++中有两个操作符提供RT ...
- C++重载(主要介绍使用友元函数重载)
重载限制 多数C++运算符都可以用下面的方式重载.重载的运算符不必是成员函数,但必须至少有一个操作数是用户自定义的类型.下面详细介绍C++对用户定义的运算符重载的限制. 1 重载后的运算符必须至少有一 ...
随机推荐
- 第三方Push服务:Urban Airship
转自:http://blog.csdn.net/kmyhy/article/details/7355756 关于推送通知,除了苹果的APNs之外,我们还有其它选择. Urban Airship就是其中 ...
- 5个基于css3超炫的鼠标滑动按钮动画
今天给大家分享5个基于css3超炫的鼠标滑动按钮动画.这5个按钮鼠标经过的时候有超炫的动画效果.这5个按钮适用浏览器:360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之 ...
- Nice是如何做iOS客户端架构的?
一个创业产品的iOS客户端架构到底怎么做呢?现下最有活力的图片社交软件Nice的技术负责人刘诗彬将为我们解答创业产品如何实现iOS客户端架构. 分享人:刘诗彬,毕业于北京邮电大学电子信息科学与技术专业 ...
- Big String 块状数组(或者说平方分割)
Big String 给一个字符串,长度不超过 106,有两种操作: 1. 在第 i 个字符的前面添加一个字符 ch 2. 查询第 k 个位置是什么字符 操作的总数不超过 2000 如果直接模拟的话, ...
- GOF设计模式之1:单例设计模式
1.单例设计模式核心作用: 保证一个类只有一个实例,并且提供了访问该实例的全局访问点 2.常见应用场景: window的任务管理器 项目中读取配置文件一般也是一个单例模式 数据库连接池的设计也是采用单 ...
- 结合源码看nginx-1.4.0之nginx模块组织结构详解
目录 0. 摘要 1. nginx模块组织结构 2. nginx模块数据结构 3. nginx模块初始化 4. 一个简单的http模块 5. 小结 6. 参考资料 0. 摘要 nginx有五大优点:模 ...
- CSS3: border-radius边框圆角详解
border-radius 基本语法: border-radius : none | <length>{1,4} [/ <length>{1,4} ]? 取值范围: <l ...
- Windows环境下安装Redis
1:首先下载redis.从下面地址下:https://github.com/MSOpenTech/redis/releases2:创建redis.conf文件:这是一个配置文件,指定了redis的监听 ...
- javascript中Math ceil(),floor(),round()三个函数的对比
Math.ceil()执行的是向上舍入 Math.floor()执行向下舍入 Math.round()执行标准舍入 一下是一些补充: ceil():将小数部分一律向整数部分进位. 如: Math.ce ...
- 使用JDBC-ODBC读取Excel文件
以下代码我没有真正去实践,紧做为总结,方便以后查阅: 这种方法需要设置ODBC源..... 参考: http://xytang.blogspot.com/2008/02/how-to-connect- ...