zoukankan      html  css  js  c++  java
  • 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
    ", bv);}
        int bv;
    };
    class derive:public base{ public: derive(int val, double d):base(val), dv(d){} void printVal(){ printf("derive::printVal dv= %f ", dv); } double dv; }; int main(){ derive d(10, 20.00); base *b = &d; assert(derive *dp = dynamic<derive*>(b)); return 0; }

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

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

    6derive

    4. 作用原理

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

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

    一步步来debug,

     derive d(10, 20.00);

    (gdb) n

    printf("deirve address: %x ", &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结构到底是什么样的,我也没找到资料,希望有知道的同学可以和我交流,谢谢。

     

  • 相关阅读:
    洛谷 P4001 [ICPC-Beijing 2006]狼抓兔子
    杂题20201201
    杂题20210103
    杂题20201010
    杂题20200928
    ACL1 Contest 1 简要题解
    杂题20200906
    杂题20200623
    USACO2020DEC Gold/Platinum 解题报告
    CSP-S2020游记
  • 原文地址:https://www.cnblogs.com/coderkian/p/3657736.html
Copyright © 2011-2022 走看看