C 物件記憶體布局測試總結 Z

2021-08-30 22:11:54 字數 2209 閱讀 3861

對於普通的c++物件記憶體布局,簡單得不得了,就不做總結了。這裡只總結涉及到虛擬繼承的情況。

因為不同編譯器對虛擬繼承的實現採用不同的方式,所以要完整的分析是不可能的。這裡只考慮vs2005/2008,還有簡單涉及gcc編譯器。

1、單個虛擬繼承

只是為了分析而已,實際中並沒有太大的作用。跟虛擬繼承相關的派生類物件的記憶體布局跟具體的編譯器相關。

(1)vs編譯器:無論有無虛函式,必然含有虛基類表指標。虛基類表中的內容為本類例項的偏移和基類例項的相對偏移值。如果有虛函式,那麼基類的虛函式表跟派生類的虛函式表是分開的。

在記憶體布局上,位址從低到高,順序如下:派生類的虛函式表指標+虛基類表指標+派生類的成員變數+「間隔」(4個位元組)+基類的虛函式表指標+基類的成員變數。派生類跟基類例項的位置關係跟普通繼承正好相反。

說明:「間隔」產生的原因是派生類重寫了基類的虛函式。如果沒重寫,則這一項沒有。

圖 1 vs編譯器—單個虛擬繼承

(2)gnu的gcc編譯器:跟vs的編譯器類似,有不同的地方是,虛基類表跟派生類的虛函式表合併。另外通過虛基類表指標往正負兩個方向定址,可以獲得 不同偏移值,也就是說有兩個功能一樣的虛函式表。不過在實際應用的時候,不知道虛基類表是否真的有用,測試了簡單的情況發現編譯器做了優化,根本就沒有用 虛基類表來定址虛基類例項。

圖 2 gcc編譯器—單個虛擬繼承

2、虛擬繼承多個基類

虛基類表要增加內容,有n個虛基類就有n項基類例項偏移值,再加上1項本類例項的偏移值,也就是n+1。

假設c虛擬繼承了a類和b類,考慮最複雜的情況(都有虛函式),那麼c類物件的記憶體布局如下

(vs編譯器):

c類虛函式表指標+虛基類表指標+c類成員變數+a類間隔(4個位元組) + a類虛函式表指標+ a類成員變數+ b類間隔(4個位元組)+b類虛函式表指標+ b類成員變數。

說明:當派生類重寫了該基類的虛函式,才會有「間隔」。「間隔」屬於虛函式被重新實現了的虛基類,可能是乙個標誌,也有可能是在函式呼叫的時候用上。不是很清楚。

圖 3 vs編譯器—虛擬繼承多個基類

(gcc編譯器):

c類虛函式表指標(包含虛基類表) + c類成員變數 + a類虛函式表指標 +  a類成員變數 + b類虛函式表指標 + b類成員變數。

相比較執行,使用gcc編譯器,派生類物件小一些。(圖略)

3、虛擬繼承之菱形繼承

這裡的菱形繼承指的是:b、c虛擬繼承a,然後d普通繼承b、c。

d類的物件的記憶體布局如下

(vs編譯器)

b類虛函式表指標(該虛函式表包含d類獨有的虛函式的位址)+b類虛基類表指標+b類成員變數+c類虛函式表指標+c類虛基類表指標+c類成員變數+d類成員變數+「間隔」+a類虛函式表指標+a類成員變數。

說明:如果a類的虛函式沒有被重寫,那麼就沒有「間隔」。

圖 4 vs編譯器—菱形繼承

(gcc編譯器)

把b、c類的虛函式表跟虛基類表合併就是了。(圖略)

4、vs編譯器,「間隔」的疑問

「間隔」的問題,在沒有虛函式的情況下,重寫是沒有「間隔」的,所以覺得可能跟虛函式有關,也就是說是為了實現多型, 具體是用在哪個地方,做了簡單的反彙編除錯(父類指標指向子類物件,呼叫被子類重寫了的虛函式),並沒有發現**用到了「間隔」,可能要在複雜的呼叫才會 用上吧,目前搞不清楚。

5、虛基類表的問題

通過反彙編除錯發現在使用多型的時候,vs編譯器會去使用虛基類表,用於定址虛基類位址。而gcc編譯器則沒有這麼做,測試了比較簡單的情況,發現它做了優化,並沒有利用虛基類表,而是直接在派生類物件位址上加上乙個常數,獲得虛基類例項的位址。

C 物件記憶體布局

好文要記下來 上 下 玄機逸士系列 補充一點,兩個博文裡面都沒有給出虛基類表中的第一項的解釋,其實第一項就是vbptr到自己類物件位址的偏移量。若沒有虛函式,也就是沒有vfptr,偏移量為0,若有,就為 4 vfptr 在 vbptr之前,所以是 4 玄機逸士的結論 vc 6 其一,只要涉及到虛基類...

C 物件記憶體布局

單一的一般繼承 可見以下幾個方面 1.虛函式表在最前面的位置 2.成員變數根據其繼承和宣告的順序一次放在後面 3.在單一繼承中,被 overwrite 的虛函式在虛函式表中得到更新 多重繼承 我們可以看到 1.每個父類都有自己的虛函式表 2.子類的成員函式被放在第乙個父類的表中 3.記憶體布局中,父...

C 記憶體物件布局

本章主要介紹了c 類中成員變數 函式物件的在記憶體中布局.當c 類中不包含virtual機制類的函式時,內部nostatic member被包含在每乙個class object之中,就想c struct一樣,而member function雖然含在class宣告之內,卻不出現在object之中,每乙...