程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> c++之RTTI介紹

c++之RTTI介紹

編輯:C++入門知識

本文介紹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異常。

 (  printVal(){printf(
 derive:  val,  d):,  *b = &*dp = dynamic<derive*> 

typeid可以作用於任意表達式或類型,當運算對象不屬於類類型或不包含虛函數時,返回運算對象的靜態類型,否則typeid會直到運行時才決定其動態類型。typeid返回的值是type_info類型對象,type_info::name()返回類型的名字,當然這是編譯器相關的。一般用來判斷兩個對象動態類型是否相同或者某個對象是否是指定類型

printf(, typeid(derive).name());

6derive

4. 作用原理

那麼dynamic_cast和typeid是怎樣知道對象的實際類型的,在《inside the c++ object model》中反復提到類型信息是在虛函數表的第一個slot中的,不過這個跟編譯器實現出入很大,根據我的上篇文章可以發現gcc實現的虛函數表放的全是虛函數,並沒有類型信息。

derive d(, , &d);

一步步來debug,

 derive d(10, 20.00);

(gdb) n

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

(gdb)

deirve address: bffff2a0

(gdb) x /4a 0xbffff2a0

0xbffff2a0:      0xa 0x0 0x40340000

d的地址是0xbffff2a0, 第一個是虛函數表指針 0x80487e0,可以發現虛函數表在_ZTV6derive往後8個字節處,_ZTV6derive又是什麼?

(gdb) x /16a  0x80487d0

0x80487d0: 0x0 0x40340000 0x0

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

0x80487f0 <_ZTV4base+8>: 0x8048674 <_ZN4base8printValEv> 0x72656436 0x657669  

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結構到底是什麼樣的,我也沒找到資料,希望有知道的同學可以和我交流,謝謝。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved