前一段時間再次拜讀《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按照聲明順序依次存儲。
對應的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:
繼承關系圖:
使用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