C++ vtordisp的應用場景分析
問題代碼
#include <iostream>
using namespace std;
class base
{
public:
base() {}
virtual void show() { cout << "base:: show"<<endl; }
private:
int ma;
};
class derive:virtual public base
{
public:
derive() {}
virtual void show() { cout << "derive:: show"; }
private:
int mb;
};
int main()
{
cout << sizeof(derive) << endl;
}以上代碼類大小常規(guī)來說應該是如下,占16個字節(jié)大小,但是為何是20呢
預期結構
class derive size(16):
+---
0 | {vbptr}
4 | mb
+---
+--- (virtual base base)
8 | {vfptr}
12 | ma
+---實際結構,占大小20個字節(jié)
class derive size(20):
+---
0 | {vbptr}
4 | mb
+---
8 | (vtordisp for vbase base)
+--- (virtual base base)
12 | {vfptr}
16 | ma
+---
derive::$vbtable@:
0 | 0
1 | 12 (derived(derive+0)base)
derive::$vftable@:
| -12
0 | &(vtordisp) derive::show
derive::show this adjustor: 12
vbi: class offset o.vbptr o.vbte fVtorDisp
base 12 0 4 1
經過驗證 必須滿足以下兩個條件
- 派生類重寫了虛基類的虛函數。
- 派生類定義了構造函數或者析構函數。
才會產生vtordisp.
這就牽扯到vtordisp了,介紹如下
1. 基本概念回顧
在 C++ 中,當涉及虛繼承時,為了確保在派生類對象中能正確定位虛基類的子對象(包含虛基類的數據成員、虛函數等內容),編譯器會在派生類對象的內存布局中安排虛基類表指針等相關結構來記錄偏移量信息,以實現準確訪問虛基類部分。同時,對于有虛函數的類,會存在虛函數表(VTable)來支持多態(tài)調用。
而 vtordisp 主要用于處理虛繼承和虛函數結合場景下,構造函數和析構函數中對虛基類指針調整的一種機制,它本質上是編譯器為了正確處理對象的初始化和析構順序、保證虛基類相關操作的正確性而引入的一個額外的字節(jié)(在 32 位系統下通常是 4 字節(jié),64 位系統下通常是 8 字節(jié))來存儲偏移量相關信息。
2. 應用場景
虛繼承與虛函數并存的類層次結構
- 場景描述:當類層次結構中既有虛繼承又有類自身包含虛函數的情況時,在派生類的構造函數和析構函數中,需要準確地處理與虛基類相關的初始化和清理工作,同時還要考慮虛函數機制帶來的多態(tài)性影響。
3. 編譯器相關考慮
- 不同的編譯器對于
vtordisp的處理可能會有一些差異,有些編譯器可能會根據具體的類層次結構復雜度、是否確實存在需要調整虛基類指針偏移量的情況等來決定是否啟用vtordisp機制以及如何分配相應的字節(jié)來存儲相關信息。比如在 Visual C++ 編譯器中,對于符合特定條件的虛繼承和虛函數結合的場景,會自動插入vtordisp相關代碼來處理對象布局和操作順序問題,而在 GCC 等其他編譯器中,也有其對應的實現方式和判斷標準來確保在類似場景下的代碼正確性。
如果不想要vtordisp 可以加 #pragma vtordisp(off) 進行關閉。
vtordisp是Visual C++編譯器的一個特性,主要用于解決在類繼承中,虛函數的調用與對象布局的問題。當你在類中使用了虛函數,并且該類被繼承,且繼承類覆蓋了基類的虛函數時,可能會出現所謂的"跳躍問題"(slicing problem)。
"跳躍問題"是指當你有一個基類的指針指向派生類對象,并且調用了虛擬函數,預期是派生類的函數被調用,但實際上可能會調用基類的函數。這是因為編譯器為了能夠快速地調用虛擬函數,直接使用了指針的偏移量來計算虛擬函數的地址,而不是檢查實際對象的類型。
為了解決這個問題,當你在類中有一個或多個虛擬函數,并且類被繼承,且派生類覆蓋了基類的虛函數時,編譯器可能會為類添加一個額外的隱藏成員,稱為vtordisp字段。vtordisp字段的作用是在構造函數和析構函數執(zhí)行過程中,記錄對象的實際類型信息,以便正確地調用虛擬函數。具體由編譯器進行管理。
在網上搜集資料并未搞清楚其底層原理,請知道的大佬不吝賜教。
到此這篇關于C++ vtordisp的應用場景的文章就介紹到這了,更多相關C++ vtordisp應用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

