天天看點

Linux Debugging(四): 使用GDB來了解C++ 對象的記憶體布局(多重繼承,虛繼承)2、帶有虛函數的單一繼承3. 多重繼承,包含有相同的父類4. 虛拟繼承

      前一段時間再次拜讀《inside the c++ object model》 深入探索c++對象模型,有了進一步的了解,是以我也寫了四篇博文算是讀書筆記:

program transformation semantics (程式轉換語義學)

the semantics of copy constructors(拷貝構造函數之編譯背後的行為)

the semantics of constructors: the default constructor (預設構造函數什麼時候會被建立出來)

the semantics of data: data語義學 深入探索c++對象模型

     這些文章都獲得了很大的浏覽量,雖然類似的博文原來都有,可能不容易被現在仍活躍在csdn blog的各位同仁看到吧。是以萌生了接着将這這本書讀完的同時,再接着談一下我的了解,或者說讀書筆記。

     關于c++虛函數,很多博文從各個角度來探究虛函數是如何實作的,或者說編譯器是如何實作虛函數的。比較經典的文章有陳皓先生的《c++虛函數表解析》和《c++對象記憶體布局》。本文通過gdb來從另外一個角度來了解c++

object的記憶體布局,一來熟悉語言背後編譯器為了實作語言特性為我們做了什麼;二來熟悉使用gdb來調試程式。

      同時,本文也将對如何更好的了解c++語言提供了一個方法:使用gdb,可以很直覺的了解編譯器的實作,從根本上掌握c++!我們不單單隻會開車,還應該知道車的内部的構造。

編譯時不要忘記-g,使得gdb可以把各個位址映射成函數名。

解釋一下gdb的指令:

set p obj <on/off>: 在c++中,如果一個對象指針指向其派生類,如果打開這個選項,gdb會自動按照虛方法調用的規則顯示輸出,如果關閉這個選項的話,gdb就不管虛函數表了。這個選項預設是off。 使用show print object檢視對象選項的設定。

set p pertty <on/off>: 按照層次列印結構體。可以從設定前後看到這個差別。on的确更容易閱讀。

就是列印虛函數表了。因為知道是兩個,可以僅僅列印2個元素。為了知道下一個存儲了什麼資訊,我們列印了3個值。實際上後幾個元素存儲了parent 和child的typeinfo name和typeinfo。

總結:

對于單一繼承,

1. vptr存儲到了object的開始。

2. 在vptr之後,從parent開始的data member按照聲明順序依次存儲。

Linux Debugging(四): 使用GDB來了解C++ 對象的記憶體布局(多重繼承,虛繼承)2、帶有虛函數的單一繼承3. 多重繼承,包含有相同的父類4. 虛拟繼承

對應的c++codes:

使用gdb列印的對象記憶體布局:

可見v3d有兩個vptr,指向不同的vtable。首先看一下第一個:

你可以注意到了,vtable列印分行了,可以使用 set p array on将列印的數組分行,以逗号結尾。

注意到該虛函數表以

結尾。在單一繼承中是沒有這個結束辨別的。

接着看第二個vtable:

當然這個隻是為了舉個例子。現實中很少有人這麼幹吧。比如通路foo,下面的code将會導緻歧義性錯誤:

 error: request for member boo is ambiguous

multiinheritance.cpp:8: error: candidates are: virtual void point2d::boo()

隻能指定具體的subobject才能進行具體調用:

c++ codes:

繼承關系圖:

Linux Debugging(四): 使用GDB來了解C++ 對象的記憶體布局(多重繼承,虛繼承)2、帶有虛函數的單一繼承3. 多重繼承,包含有相同的父類4. 虛拟繼承

使用gdb列印object的記憶體布局:

gdb列印的vptr相關:

有興趣的話可以看一下反彙編的vtable的構成。

參考:

1. http://stackoverflow.com/questions/6191678/print-c-vtables-using-gdb

2. http://stackoverflow.com/questions/18363899/how-to-display-a-vtable-by-name-using-gdb

尊重原創,轉載請注明出處: anzhsoft http://blog.csdn.net/anzhsoft/article/details/18600163

繼續閱讀