浅议 Dynamic_cast 和 RTTI

本文详细介绍了C++中的RTTI(运行时类型信息)机制及其与static_cast和dynamic_cast的关系。通过实例代码展示了这两种类型转换操作符的使用场景及它们在编译时与运行时的不同行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 写这篇博文的目的是,记录学习过程。  
  2.   
  3. 对于问题要较真,在解决这个问题中会学到很多,远远超过自己期望,锻炼思维,享受这个过程。  
  4.   
  5. 问题: Static_cast 与 Dynamic_cast的区别  
  6. 来自书本上的解释:  
  7.   
  8.   用 static_cast<type-id > ( expression )    
  9.   
  10. 1. static_cast(expression) The static_cast<>() is used to cast between the integer types. 'e.g.' char->longint->short etc.  
  11.   
  12.    用来数值之间的转化。  
  13.   
  14. 2.  可以在相关指针之间转换,指针在void * 之间转换,还可以在基类和派生类之间转换。 这些转换是在编译的时候就确定下来转换(无非就是根据继承关系,偏移指针而已),但是这需要自己保证安全。  
  15.   
  16.    比如  
  17.   
  18. #include <iostream>  
  19. using namespace std;  
  20.   
  21. class Base   
  22. {  
  23. public:  
  24.     virtual void f() {cout<<"Base::f()"<<endl;}  
  25.   
  26. };  
  27.   
  28. class Derive: public Base  
  29. {  
  30. public:  
  31.     virtual  void f() {cout<<"Derive::f()"<<endl;}  
  32.     virtual  void f2() {cout<<"Derive::f1()"<<endl;}  
  33.   
  34. };  
  35.   
  36.   
  37. int main()  
  38. {  
  39.   
  40.     Base *pbase1  = new Derive();  
  41.     Derive* pderive1 = static_cast<Derive *>(pbase1);  
  42.     pderive1->f(); // Derive::f()  
  43.       
  44.     Base* pbase2 = new Base();  
  45.     Derive * pderive2 = static_cast<Derive *>(pbase2);  
  46.     pderive2->f();  // Base::f()  
  47.     pderive2->f2(); // throw exception "Access violation reading"  
  48.   
  49.     delete pbase1;  
  50.     delete pbase2;  
  51.   
  52. }  
  53.   
  54.   
  55. 虽然 由 pbase2 转化到 pderive2 ,编译器编译正确。 但是当调用 pderive2->f(); 应该不是希望的; 调用pderive2->f2() 因为基类本身就没有这个函数,说以运行时出错,抛出异常。  
  56.   
  57. 所以说static_cast 是编译时确定下来,需要自己确保转换类型安全,否则运行时会抛出异常.  
  58.   
  59.  注意static_cast 不能直接在没有继承关系的对象指针之间进行转换。在Com 里面实现不同接口的同个对象,其也不能再接口之间转换(更何况是动态的),所以COM提供一个query 借口。  
  60.   
  61.   
  62. 用法:dynamic_cast < type-id > ( expression)  
  63.   
  64. 是专门用于具有继承关系的类之间转换的,尤其是向下类型转换,是安全的。  
  65.   
  66. #include <iostream>  
  67. using namespace std;  
  68.   
  69. class Base  
  70. {  
  71. public:  
  72. virtual void f() {cout<<"Base::f()"<<endl;}  
  73.   
  74. };  
  75.   
  76. class Derive: public Base  
  77. {  
  78. public:  
  79. virtual void f() {cout<<"Derive::f()"<<endl;}  
  80. virtual void f2() {cout<<"Derive::f1()"<<endl;}  
  81.   
  82. };  
  83.   
  84. int main()  
  85. {  
  86.   
  87. Base *pbase1 = new Derive();  
  88. Derive* pderive1 = dynamic_cast<Derive *>(pbase1); //down-cast  
  89. pderive1->f(); // Derive::f()  
  90.   
  91. Base* pbase2 = new Base();  
  92. Derive * pderive2 = dynamic_cast<Derive *>(pbase2); //up-cast  
  93.   
  94. if ( pderive2) // NULL  
  95. {  
  96. pderive2->f();  
  97. pderive2->f2();  
  98. }  
  99.   
  100. delete pbase1;  
  101. delete pbase2;  
  102.   
  103. }  
  104. dynamic_cast 如何保证转换是安全的? 如何知道具体该类的具体类型 以及 继承关系呢?   
  105.   
  106. 引入RTTI,其存储着类运行的相关信息, 比如类的名字,以及类的基类。下面就介绍RTTI。  
  107.   
  108.   
  109.   
  110. 2. RTTI (Run Time Type info)  
  111.   这个神奇的东西用于存储类的相关信息,用于在运行时识别类对象的信息。C++ 里面只记录的类的名字和类的继承关系链。使得编译成二进制的代码,对象可以知道自己的名字(ASCII),以及在继承链中的位置。  
  112.   
  113.   C++ 里面提供 一个关键字 typeid , 一个数据类型 typeinfo,以及对应的头文件 typeinfo.h  
  114.   
  115.  1 #include <iostream>  
  116.  2 #include <typeinfo>  
  117.  3  using namespace std;  
  118.  4   
  119.  5  class Base   
  120.  6 {  
  121.  7  public:  
  122.  8     virtual void f() {}  // it must need the virtual table  
  123.  9 };  
  124. 10   
  125. 11   
  126. 12  class Derive: public Base  
  127. 13 {  
  128. 14   
  129. 15 };  
  130. 16   
  131. 17   
  132. 18  class Derive2: public Base  
  133. 19 {  
  134. 20    
  135. 21 };  
  136. 22   
  137. 23  void f(Base* pbase)  
  138. 24 {  
  139. 25   const type_info& typeinfo = typeid(pbase);  
  140. 26   cout << typeinfo.name()<<endl;  
  141. 27   
  142. 28   
  143. 29   if(NULL != dynamic_cast<Derive*>(pbase))  
  144. 30   {  
  145. 31       cout<<"type: Derive"<<endl;  
  146. 32   }  
  147. 33   else if(NULL != dynamic_cast<Derive2*>(pbase))  
  148. 34   {  
  149. 35       cout<<"type: Derive2"<<endl;  
  150. 36   }  
  151. 37   else  
  152. 38   {  
  153. 39        //ASSERT(0)  
  154. 40    }  
  155. 41 }  
  156. 42   
  157. 43   
  158. 44  int main()  
  159. 45 {  
  160. 46     Base *pbase1  = new Derive();  
  161. 47     f(pbase1);  
  162. 48   
  163. 49     Base* pbase = new Derive2();  
  164. 50     f(pbase);  
  165. 51 }  
  166. out put:  
  167.   
  168. class Base *  
  169. 2 type: Derive  
  170. 3  class Base *  
  171. 4 type: Derive2  
  172. 可见 Dynamic 是运行时确定的,是安全的。 那么  
  173.   
  174. 1. RTTI 的信息如何和对象绑定在一起?什么时候绑定的?  
  175.   
  176. 2. 为什么dynam_cast 必须要求转换的类型之间要有虚函数?否则编译通不过。  
  177.   
  178. 下面来回答这个问题。  
  179.   
  180. 3.RTTI 如何与对象绑定   
  181. google,找资料。 下面的图来自于 “Inside C++ Model”, RTTI 的info 是如何和对象之间的关系:  
  182.   
  183. class Point   
  184. {   
  185.   
  186. public:   
  187.   
  188.    Point( float xval );   
  189.   
  190.    virtual ~Point();   
  191.   
  192.    float x() const;   
  193.   
  194.    static int PointCount();   
  195.   
  196. protected:   
  197.   
  198.    virtual ostream& print( ostream &os ) const;   
  199.   
  200.    float _x;   
  201.   
  202.    static int _point_count;   
  203.   
  204. };   
  205. 其内存中模型:  
  206.   
  207.   
  208.   
  209. 明显RTTI info 存在于虚表的第一项。第二个问题就可以回答,因为RTTI 依赖于虚表,所以用dynamic_cast 对应的类一定要有虚函数。  
  210.   
  211. 下面在VC中验证一下,  
  212.   
  213. 在VC中,我们知道虚指针指向虚表,对应的虚表第一项就是第一个虚函数。如果我们认为虚函数构成虚表,那么就可以认为RTTI info 就走虚表的紧邻上面。   
  214.   
  215. 下面验证:  
  216.   
  217. 1. 在VC 中查看RTTI中类名字  
  218.   
  219.   
  220.   
  221. 从上面图表可见,RTTI 对应的内容是空的。那么VC的实现和 书中的模型不一致吗?难道RTTI不在虚表的上面吗 ?接着有了下面的验证:  
  222.   
  223. 2. 把虚表上面指向RTTI info 的地址,给设置为0, 那么typeid 还可以工作吗? Dynamic_cast 还可以工作吗?如果还可以工作,则说明这个地址指向的数据无关。  
  224.   
  225.   
  226.   
  227.   如果将虚表上的RTTI的指针置空,dynamic_cast 就不能运行,抛出异常“std:: __non_rtti_object” . 那说明这个地址,还是与RTTI有关。 那问题出在哪里?  
  228.   
  229. 尝试在google 里面搜索,但是未果。 那么Dynamic_cast 的依赖于 RTTI的信息,那么Dynamic_cast的实现着手看看. 查看一下 他的汇编代码。 于是有了下面的实验。  
  230.   
  231. 3. RTTI 在VC里面如何实现的。  
  232.   
  233.   将上面的代码以汇编形式输出,查看。   
  234.   
  235. 24   :     Derive * pderive = dynamic_cast<Derive*>(pbase);  
  236.   
  237.     push    0  
  238.     push    OFFSET ??_R0?AVDerive@@@8  
  239.     push    OFFSET ??_R0?AVBase@@@8  
  240.     push    0  
  241.     mov    eax, DWORD PTR _pbase$[ebp]  
  242.     push    eax  
  243.     call    ___RTDynamicCast  
  244.     add    esp, 20                    ; 00000014H  
  245.     mov    DWORD PTR _pderive$[ebp], eax  
  246. 发现 dynamic_cast的实现依赖于 对象本身,以及 ??_R0?AVDerive@@@8 和 ??_R0?AVBase@@@8 .  于是继续查看代码  
  247.   
  248. View Code   1 ; Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.762   
  249.   2    
  250.   3     TITLE    c:\Documents and Settings\zhangroc\Desktop\TW\Test\static_cast\static_cast.cpp  
  251.   4     .686P  
  252.   5     .XMM  
  253.   6     include listing.inc  
  254.   7     .model    flat  
  255.   8   
  256.   9 INCLUDELIB MSVCRTD  
  257.  10 INCLUDELIB OLDNAMES  
  258.  11   
  259.  12 PUBLIC    ??_C@_0P@GHFPNOJB@bad?5allocation?$AA@        ; `string'  
  260.  13  _DATA    SEGMENT  
  261.  14 __bad_alloc_Message DD FLAT:??_C@_0P@GHFPNOJB@bad?5allocation?$AA@  
  262.  15 _DATA    ENDS  
  263.  16  ;    COMDAT ??_C@_0P@GHFPNOJB@bad?5allocation?$AA@  
  264.  17  CONST    SEGMENT  
  265.  18 ??_C@_0P@GHFPNOJB@bad?5allocation?$AA@ DB 'bad allocation', 00H ; `string'  
  266.  19  CONST    ENDS  
  267.  20 PUBLIC    ??_R0?AVBase@@@8                ; Base `RTTI Type Descriptor'  
  268.  21  PUBLIC    ??_R0?AVDerive@@@8                ; Derive `RTTI Type Descriptor'  
  269.  22  PUBLIC    ??0Derive@@QAE@XZ                ; Derive::Derive  
  270.  23  PUBLIC    _main  
  271.  24 EXTRN    ___RTDynamicCast:PROC  
  272.  25 EXTRN    ??2@YAPAXI@Z:PROC                ; operator new  
  273.  26  EXTRN    __RTC_CheckEsp:PROC  
  274.  27 EXTRN    __RTC_Shutdown:PROC  
  275.  28 EXTRN    __RTC_InitBase:PROC  
  276.  29 EXTRN    ??_7type_info@@6B@:QWORD            ; type_info::`vftable'  
  277.  30 ;    COMDAT ??_R0?AVBase@@@8  
  278.  31 ; File c:\documents and settings\zhangroc\desktop\tw\test\static_cast\static_cast.cpp  
  279.  32  _DATA    SEGMENT  
  280.  33 ??_R0?AVBase@@@8 DD FLAT:??_7type_info@@6B@        ; Base `RTTI Type Descriptor'  
  281.  34      DD    00H  
  282.  35     DB    '.?AVBase@@', 00H  
  283.  36 _DATA    ENDS  
  284.  37  ;    COMDAT ??_R0?AVDerive@@@8  
  285.  38 _DATA    SEGMENT  
  286.  39 ??_R0?AVDerive@@@8 DD FLAT:??_7type_info@@6B@        ; Derive `RTTI Type Descriptor'  
  287.  40     DD    00H  
  288.  41     DB    '.?AVDerive@@', 00H  
  289.  42 _DATA    ENDS  
  290.  43 ;    COMDAT rtc$TMZ  
  291.  44 rtc$TMZ    SEGMENT  
  292.  45 __RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown  
  293.  46 rtc$TMZ    ENDS  
  294.  47 ;    COMDAT rtc$IMZ  
  295.  48 rtc$IMZ    SEGMENT  
  296.  49 __RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase  
  297.  50 ; Function compile flags: /Odtp /RTCsu /ZI  
  298.  51 rtc$IMZ    ENDS  
  299.  52 ;    COMDAT _main  
  300.  53 _TEXT    SEGMENT  
  301.  54 tv69 = -256                        ; size = 4  
  302.  55 $T3121 = -248                        ; size = 4  
  303.  56 _pderive$ = -44                        ; size = 4  
  304.  57 _rtti$ = -32                        ; size = 4  
  305.  58 _ptable$ = -20                        ; size = 4  
  306.  59 _pbase$ = -8                        ; size = 4  
  307.  60 _main    PROC                        ; COMDAT  
  308.  61   
  309.  62 ; 19   : {  
  310.  63   
  311.  64     push    ebp  
  312.  65     mov    ebp, esp  
  313.  66     sub    esp, 256                ; 00000100H  
  314.  67     push    ebx  
  315.  68     push    esi  
  316.  69     push    edi  
  317.  70     lea    edi, DWORD PTR [ebp-256]  
  318.  71     mov    ecx, 64                    ; 00000040H  
  319.  72     mov    eax, -858993460                ; ccccccccH  
  320.  73     rep stosd  
  321.  74   
  322.  75 ; 20   :     Base *pbase  = new Derive();  
  323.  76   
  324.  77     push    4  
  325.  78     call    ??2@YAPAXI@Z                ; operator new  
  326.  79     add    esp, 4  
  327.  80     mov    DWORD PTR $T3121[ebp], eax  
  328.  81     cmp    DWORD PTR $T3121[ebp], 0  
  329.  82     je    SHORT $LN3@main  
  330.  83     mov    ecx, DWORD PTR $T3121[ebp]  
  331.  84     call    ??0Derive@@QAE@XZ  
  332.  85     mov    DWORD PTR tv69[ebp], eax  
  333.  86     jmp    SHORT $LN4@main  
  334.  87 $LN3@main:  
  335.  88     mov    DWORD PTR tv69[ebp], 0  
  336.  89 $LN4@main:  
  337.  90     mov    eax, DWORD PTR tv69[ebp]  
  338.  91     mov    DWORD PTR _pbase$[ebp], eax  
  339.  92   
  340.  93 ; 21   :     int *ptable = (int*)(*(int*)pbase);  
  341.  94   
  342.  95     mov    eax, DWORD PTR _pbase$[ebp]  
  343.  96     mov    ecx, DWORD PTR [eax]  
  344.  97     mov    DWORD PTR _ptable$[ebp], ecx  
  345.  98   
  346.  99 ; 22   :     int *rtti = ptable -1;  
  347. 100   
  348. 101     mov    eax, DWORD PTR _ptable$[ebp]  
  349. 102     sub    eax, 4  
  350. 103     mov    DWORD PTR _rtti$[ebp], eax  
  351. 104   
  352. 105 ; 23   :       
  353. 106 ; 24   :     Derive * pderive = dynamic_cast<Derive*>(pbase);  
  354. 107   
  355. 108     push    0  
  356. 109     push    OFFSET ??_R0?AVDerive@@@8  
  357. 110     push    OFFSET ??_R0?AVBase@@@8  
  358. 111     push    0  
  359. 112     mov    eax, DWORD PTR _pbase$[ebp]  
  360. 113     push    eax  
  361. 114     call    ___RTDynamicCast  
  362. 115     add    esp, 20                    ; 00000014H  
  363. 116     mov    DWORD PTR _pderive$[ebp], eax  
  364. 117   
  365. 118 ; 25   :      
  366. 119 ; 26   : }  
  367. 120   
  368. 121     xor    eax, eax  
  369. 122     pop    edi  
  370. 123     pop    esi  
  371. 124     pop    ebx  
  372. 125     add    esp, 256                ; 00000100H  
  373. 126     cmp    ebp, esp  
  374. 127     call    __RTC_CheckEsp  
  375. 128     mov    esp, ebp  
  376. 129     pop    ebp  
  377. 130     ret    0  
  378. 131 _main    ENDP  
  379. 132 _TEXT    ENDS  
  380. 133 PUBLIC    ??_7Derive@@6B@                    ; Derive::`vftable'  
  381. 134 PUBLIC    ??0Base@@QAE@XZ                    ; Base::Base  
  382. 135 PUBLIC    ??_R4Derive@@6B@                ; Derive::`RTTI Complete Object Locator'  
  383. 136 PUBLIC    ??_R3Derive@@8                    ; Derive::`RTTI Class Hierarchy Descriptor'  
  384. 137 PUBLIC    ??_R2Derive@@8                    ; Derive::`RTTI Base Class Array'  
  385. 138 PUBLIC    ??_R1A@?0A@EA@Derive@@8                ; Derive::`RTTI Base Class Descriptor at (0,-1,0,64)'  
  386. 139 PUBLIC    ??_R1A@?0A@EA@Base@@8                ; Base::`RTTI Base Class Descriptor at (0,-1,0,64)'  
  387. 140 PUBLIC    ??_R3Base@@8                    ; Base::`RTTI Class Hierarchy Descriptor'  
  388. 141 PUBLIC    ??_R2Base@@8                    ; Base::`RTTI Base Class Array'  
  389. 142 PUBLIC    ?f@Base@@UAEXXZ                    ; Base::f  
  390. 143 ;    COMDAT ??_R2Base@@8  
  391. 144 rdata$r    SEGMENT  
  392. 145 ??_R2Base@@8 DD    FLAT:??_R1A@?0A@EA@Base@@8        ; Base::`RTTI Base Class Array'  
  393. 146 rdata$r    ENDS  
  394. 147 ;    COMDAT ??_R3Base@@8  
  395. 148 rdata$r    SEGMENT  
  396. 149 ??_R3Base@@8 DD    00H                    ; Base::`RTTI Class Hierarchy Descriptor'  
  397. 150     DD    00H  
  398. 151     DD    01H  
  399. 152     DD    FLAT:??_R2Base@@8  
  400. 153 rdata$r    ENDS  
  401. 154 ;    COMDAT ??_R1A@?0A@EA@Base@@8  
  402. 155 rdata$r    SEGMENT  
  403. 156 ??_R1A@?0A@EA@Base@@8 DD FLAT:??_R0?AVBase@@@8        ; Base::`RTTI Base Class Descriptor at (0,-1,0,64)'  
  404. 157     DD    00H  
  405. 158     DD    00H  
  406. 159     DD    0ffffffffH  
  407. 160     DD    00H  
  408. 161     DD    040H  
  409. 162     DD    FLAT:??_R3Base@@8  
  410. 163 rdata$r    ENDS  
  411. 164 ;    COMDAT ??_R1A@?0A@EA@Derive@@8  
  412. 165 rdata$r    SEGMENT  
  413. 166 ??_R1A@?0A@EA@Derive@@8 DD FLAT:??_R0?AVDerive@@@8    ; Derive::`RTTI Base Class Descriptor at (0,-1,0,64)'  
  414. 167     DD    01H  
  415. 168     DD    00H  
  416. 169     DD    0ffffffffH  
  417. 170     DD    00H  
  418. 171     DD    040H  
  419. 172     DD    FLAT:??_R3Derive@@8  
  420. 173 rdata$r    ENDS  
  421. 174 ;    COMDAT ??_R2Derive@@8  
  422. 175 rdata$r    SEGMENT  
  423. 176 ??_R2Derive@@8 DD FLAT:??_R1A@?0A@EA@Derive@@8        ; Derive::`RTTI Base Class Array'  
  424. 177     DD    FLAT:??_R1A@?0A@EA@Base@@8  
  425. 178 rdata$r    ENDS  
  426. 179 ;    COMDAT ??_R3Derive@@8  
  427. 180 rdata$r    SEGMENT  
  428. 181 ??_R3Derive@@8 DD 00H                    ; Derive::`RTTI Class Hierarchy Descriptor'  
  429. 182     DD    00H  
  430. 183     DD    02H  
  431. 184     DD    FLAT:??_R2Derive@@8  
  432. 185 rdata$r    ENDS  
  433. 186 ;    COMDAT ??_R4Derive@@6B@  
  434. 187 rdata$r    SEGMENT  
  435. 188 ??_R4Derive@@6B@ DD 00H                    ; Derive::`RTTI Complete Object Locator'  
  436. 189     DD    00H  
  437. 190     DD    00H  
  438. 191     DD    FLAT:??_R0?AVDerive@@@8  
  439. 192     DD    FLAT:??_R3Derive@@8  
  440. 193 rdata$r    ENDS  
  441. 194 ;    COMDAT ??_7Derive@@6B@  
  442. 195 CONST    SEGMENT  
  443. 196 ??_7Derive@@6B@ DD FLAT:??_R4Derive@@6B@        ; Derive::`vftable'  
  444. 197     DD    FLAT:?f@Base@@UAEXXZ  
  445. 198 ; Function compile flags: /Odtp /RTCsu /ZI  
  446. 199 CONST    ENDS  
  447. 200 ;    COMDAT ??0Derive@@QAE@XZ  
  448. 201 _TEXT    SEGMENT  
  449. 202 _this$ = -8                        ; size = 4  
  450. 203 ??0Derive@@QAE@XZ PROC                    ; Derive::Derive, COMDAT  
  451. 204 ; _this$ = ecx  
  452. 205     push    ebp  
  453. 206     mov    ebp, esp  
  454. 207     sub    esp, 204                ; 000000ccH  
  455. 208     push    ebx  
  456. 209     push    esi  
  457. 210     push    edi  
  458. 211     push    ecx  
  459. 212     lea    edi, DWORD PTR [ebp-204]  
  460. 213     mov    ecx, 51                    ; 00000033H  
  461. 214     mov    eax, -858993460                ; ccccccccH  
  462. 215     rep stosd  
  463. 216     pop    ecx  
  464. 217     mov    DWORD PTR _this$[ebp], ecx  
  465. 218     mov    ecx, DWORD PTR _this$[ebp]  
  466. 219     call    ??0Base@@QAE@XZ  
  467. 220     mov    eax, DWORD PTR _this$[ebp]  
  468. 221     mov    DWORD PTR [eax], OFFSET ??_7Derive@@6B@  
  469. 222     mov    eax, DWORD PTR _this$[ebp]  
  470. 223     pop    edi  
  471. 224     pop    esi  
  472. 225     pop    ebx  
  473. 226     add    esp, 204                ; 000000ccH  
  474. 227     cmp    ebp, esp  
  475. 228     call    __RTC_CheckEsp  
  476. 229     mov    esp, ebp  
  477. 230     pop    ebp  
  478. 231     ret    0  
  479. 232 ??0Derive@@QAE@XZ ENDP                    ; Derive::Derive  
  480. 233 ; Function compile flags: /Odtp /RTCsu /ZI  
  481. 234 _TEXT    ENDS  
  482. 235 ;    COMDAT ?f@Base@@UAEXXZ  
  483. 236 _TEXT    SEGMENT  
  484. 237 _this$ = -8                        ; size = 4  
  485. 238 ?f@Base@@UAEXXZ PROC                    ; Base::f, COMDAT  
  486. 239 ; _this$ = ecx  
  487. 240   
  488. 241 ; 8    :     virtual void f() {}  
  489. 242   
  490. 243     push    ebp  
  491. 244     mov    ebp, esp  
  492. 245     sub    esp, 204                ; 000000ccH  
  493. 246     push    ebx  
  494. 247     push    esi  
  495. 248     push    edi  
  496. 249     push    ecx  
  497. 250     lea    edi, DWORD PTR [ebp-204]  
  498. 251     mov    ecx, 51                    ; 00000033H  
  499. 252     mov    eax, -858993460                ; ccccccccH  
  500. 253     rep stosd  
  501. 254     pop    ecx  
  502. 255     mov    DWORD PTR _this$[ebp], ecx  
  503. 256     pop    edi  
  504. 257     pop    esi  
  505. 258     pop    ebx  
  506. 259     mov    esp, ebp  
  507. 260     pop    ebp  
  508. 261     ret    0  
  509. 262 ?f@Base@@UAEXXZ ENDP                    ; Base::f  
  510. 263 _TEXT    ENDS  
  511. 264 PUBLIC    ??_7Base@@6B@                    ; Base::`vftable'  
  512. 265 PUBLIC    ??_R4Base@@6B@                    ; Base::`RTTI Complete Object Locator'  
  513. 266 ;    COMDAT ??_R4Base@@6B@  
  514. 267 rdata$r    SEGMENT  
  515. 268 ??_R4Base@@6B@ DD 00H                    ; Base::`RTTI Complete Object Locator'  
  516. 269     DD    00H  
  517. 270     DD    00H  
  518. 271     DD    FLAT:??_R0?AVBase@@@8  
  519. 272     DD    FLAT:??_R3Base@@8  
  520. 273 rdata$r    ENDS  
  521. 274 ;    COMDAT ??_7Base@@6B@  
  522. 275 CONST    SEGMENT  
  523. 276 ??_7Base@@6B@ DD FLAT:??_R4Base@@6B@            ; Base::`vftable'  
  524. 277     DD    FLAT:?f@Base@@UAEXXZ  
  525. 278 ; Function compile flags: /Odtp /RTCsu /ZI  
  526. 279 CONST    ENDS  
  527. 280 ;    COMDAT ??0Base@@QAE@XZ  
  528. 281 _TEXT    SEGMENT  
  529. 282 _this$ = -8                        ; size = 4  
  530. 283 ??0Base@@QAE@XZ PROC                    ; Base::Base, COMDAT  
  531. 284 ; _this$ = ecx  
  532. 285     push    ebp  
  533. 286     mov    ebp, esp  
  534. 287     sub    esp, 204                ; 000000ccH  
  535. 288     push    ebx  
  536. 289     push    esi  
  537. 290     push    edi  
  538. 291     push    ecx  
  539. 292     lea    edi, DWORD PTR [ebp-204]  
  540. 293     mov    ecx, 51                    ; 00000033H  
  541. 294     mov    eax, -858993460                ; ccccccccH  
  542. 295     rep stosd  
  543. 296     pop    ecx  
  544. 297     mov    DWORD PTR _this$[ebp], ecx  
  545. 298     mov    eax, DWORD PTR _this$[ebp]  
  546. 299     mov    DWORD PTR [eax], OFFSET ??_7Base@@6B@  
  547. 300     mov    eax, DWORD PTR _this$[ebp]  
  548. 301     pop    edi  
  549. 302     pop    esi  
  550. 303     pop    ebx  
  551. 304     mov    esp, ebp  
  552. 305     pop    ebp  
  553. 306     ret    0  
  554. 307 ??0Base@@QAE@XZ ENDP                    ; Base::Base  
  555. 308 _TEXT    ENDS  
  556. 309 END原来虚表上面指向是一个 Derive::`RTTI Complete Object Locator 。 用google 搜索下面的该关键字,有了下面的文章http://www.openrce.org/articles/full_view/23和该图:  
  557. 谜底揭晓: 原来虚表上面的地址是指向一个结构 Derive::`RTTI Complete Object Locator , 这个结构指向该类的名字,和其对象继承链。  
  558.   
  559. 这就回答了第一个问题,RTTI info 如何和对象绑定的? 在对象创建的时候,调用构造函时候,创建虚表以及RTTI info,这样dynamic cast 就可以去访问RTTI,从而保证安全。  
  560.   
  561. 同样有个一问题,那就是RTTI 效率底下,试下如果一个类其继承多层,而且有多继承,那么查找链就相当遍历一个链表。  
  562.   
  563. 4. 实现一个代码用来从RTTI中读取类名字  
  564.  1   #include "iostream"  
  565.  2   #include "string"   
  566.  3 #include <typeinfo>  
  567.  4   using namespace std;  
  568.  5   
  569.  6   
  570.  7   class Base  
  571.  8   {  
  572.  9   public:  
  573. 10       virtual void f() { }  
  574. 11   };  
  575. 12   
  576. 13   class Derive : public Base  
  577. 14   {  
  578. 15   };  
  579. 16   
  580. 17   typedef unsigned long DWORD;  
  581. 18   
  582. 19   struct TypeDescriptor  
  583. 20   {  
  584. 21       DWORD ptrToVTable;  
  585. 22       DWORD spare;  
  586. 23       char name[ ];  
  587. 24   };  
  588. 25    struct RTTICompleteObjectLocator  
  589. 26     
  590. 27   {  
  591. 28     
  592. 29       DWORD signature; //always zero ?  
  593. 30     
  594. 31       DWORD offset;    //offset of this vtable in the complete class  
  595. 32     
  596. 33       DWORD cdOffset;  //constructor displacement offset  
  597. 34     
  598. 35       struct TypeDescriptor* pTypeDescriptor; //TypeDescriptor of the complete class  
  599. 36     
  600. 37       int * ptr;  
  601. 38       //struct RTTIClassHierarchyDescriptor* pClassDescriptor; //describes inheritance hierarchy  
  602. 39    
  603. 40   };  
  604. 41     
  605. 42   
  606. 43 int main()  
  607. 44 {  
  608. 45       
  609. 46     Base *pderive = new Derive();  
  610. 47       
  611. 48     int **ptr = (int **)(&pderive);  
  612. 49   
  613. 50     int *ptable = (int *)(*(int *)(*ptr));   
  614. 51   
  615. 52     int * rtti = ptable -1;  
  616. 53     
  617. 54     RTTICompleteObjectLocator * RIIT_locator =   (RTTICompleteObjectLocator *)( *(int*)rtti);  
  618. 55   
  619. 56     cout<<RIIT_locator->pTypeDescriptor->name<<endl;  
  620. 57   
  621. 58 }  
  622. Out put:  
  623.   
  624. .?AVDerive@@  
  625.   
  626. 当然可以根据RTTI的信息,可以遍历其继承关系图。留作一个练习,可以尝试一下。  
  627.   
  628. 总结:  
  629.   
  630. static_cast 用于数值类型之间的转换,也可以用于指针之间的转换,编译的已经确定好,效率高,但须要自己保证其安全性。  
  631.   
  632. dynamic_cast 用于有继承关系的类之间转换,是基于RTTI数据信息的,运行时检测,安全,但是效率低。  
  633.   
  634. Refernce:  
  635.   
  636. RTTI intoduction:  
  637.   
  638. 1. http://www.rcs.hu/Articles/RTTI_Part1.htm [介绍RTTI 的应用,需要的借口,以及一个实现]  
  639.   
  640. 2. http://www.codeproject.com/KB/cpp/dynamic_cpp.aspx  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值