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呢
預期結(jié)構(gòu)
class derive size(16): +--- 0 | {vbptr} 4 | mb +--- +--- (virtual base base) 8 | {vfptr} 12 | ma +---
實際結(jié)構(gòu),占大小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
經(jīng)過驗證 必須滿足以下兩個條件
- 派生類重寫了虛基類的虛函數(shù)。
- 派生類定義了構(gòu)造函數(shù)或者析構(gòu)函數(shù)。
才會產(chǎn)生vtordisp.
這就牽扯到vtordisp了,介紹如下
1. 基本概念回顧
在 C++ 中,當涉及虛繼承時,為了確保在派生類對象中能正確定位虛基類的子對象(包含虛基類的數(shù)據(jù)成員、虛函數(shù)等內(nèi)容),編譯器會在派生類對象的內(nèi)存布局中安排虛基類表指針等相關結(jié)構(gòu)來記錄偏移量信息,以實現(xiàn)準確訪問虛基類部分。同時,對于有虛函數(shù)的類,會存在虛函數(shù)表(VTable)來支持多態(tài)調(diào)用。
而 vtordisp
主要用于處理虛繼承和虛函數(shù)結(jié)合場景下,構(gòu)造函數(shù)和析構(gòu)函數(shù)中對虛基類指針調(diào)整的一種機制,它本質(zhì)上是編譯器為了正確處理對象的初始化和析構(gòu)順序、保證虛基類相關操作的正確性而引入的一個額外的字節(jié)(在 32 位系統(tǒng)下通常是 4 字節(jié),64 位系統(tǒng)下通常是 8 字節(jié))來存儲偏移量相關信息。
2. 應用場景
虛繼承與虛函數(shù)并存的類層次結(jié)構(gòu)
- 場景描述:當類層次結(jié)構(gòu)中既有虛繼承又有類自身包含虛函數(shù)的情況時,在派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)中,需要準確地處理與虛基類相關的初始化和清理工作,同時還要考慮虛函數(shù)機制帶來的多態(tài)性影響。
3. 編譯器相關考慮
- 不同的編譯器對于
vtordisp
的處理可能會有一些差異,有些編譯器可能會根據(jù)具體的類層次結(jié)構(gòu)復雜度、是否確實存在需要調(diào)整虛基類指針偏移量的情況等來決定是否啟用vtordisp
機制以及如何分配相應的字節(jié)來存儲相關信息。比如在 Visual C++ 編譯器中,對于符合特定條件的虛繼承和虛函數(shù)結(jié)合的場景,會自動插入vtordisp
相關代碼來處理對象布局和操作順序問題,而在 GCC 等其他編譯器中,也有其對應的實現(xiàn)方式和判斷標準來確保在類似場景下的代碼正確性。
如果不想要vtordisp 可以加 #pragma vtordisp(off) 進行關閉。
vtordisp是Visual C++編譯器的一個特性,主要用于解決在類繼承中,虛函數(shù)的調(diào)用與對象布局的問題。當你在類中使用了虛函數(shù),并且該類被繼承,且繼承類覆蓋了基類的虛函數(shù)時,可能會出現(xiàn)所謂的"跳躍問題"(slicing problem)。
"跳躍問題"是指當你有一個基類的指針指向派生類對象,并且調(diào)用了虛擬函數(shù),預期是派生類的函數(shù)被調(diào)用,但實際上可能會調(diào)用基類的函數(shù)。這是因為編譯器為了能夠快速地調(diào)用虛擬函數(shù),直接使用了指針的偏移量來計算虛擬函數(shù)的地址,而不是檢查實際對象的類型。
為了解決這個問題,當你在類中有一個或多個虛擬函數(shù),并且類被繼承,且派生類覆蓋了基類的虛函數(shù)時,編譯器可能會為類添加一個額外的隱藏成員,稱為vtordisp字段。vtordisp字段的作用是在構(gòu)造函數(shù)和析構(gòu)函數(shù)執(zhí)行過程中,記錄對象的實際類型信息,以便正確地調(diào)用虛擬函數(shù)。具體由編譯器進行管理。
在網(wǎng)上搜集資料并未搞清楚其底層原理,請知道的大佬不吝賜教。
到此這篇關于C++ vtordisp的應用場景的文章就介紹到這了,更多相關C++ vtordisp應用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++中的頭文件與Extern(外部函數(shù)調(diào)用)方式
這篇文章主要介紹了C++中的頭文件與Extern(外部函數(shù)調(diào)用)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08c++如何在主函數(shù)文件中調(diào)用其他函數(shù)文件
這篇文章主要介紹了c++如何在主函數(shù)文件中調(diào)用其他函數(shù)文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08詳解設計模式中的Command命令模式及相關C++實現(xiàn)
這篇文章主要介紹了詳解設計模式中的Command命令模式及相關C++實現(xiàn),命令模式強調(diào)調(diào)用操作的對象和操作的具體實現(xiàn)者之間的解耦,需要的朋友可以參考下2016-03-03C語言數(shù)據(jù)結(jié)構(gòu)與算法之圖的遍歷(一)
這篇文章主要是介紹了利用深度優(yōu)先算法實現(xiàn)圖的遍歷,文中利用圖文詳細的介紹了實現(xiàn)步驟,對我們學習數(shù)據(jù)結(jié)構(gòu)與算法有一定的幫助,需要的朋友可以參考一下2021-12-12C語言實現(xiàn)簡易通訊錄(靜態(tài)版本)的代碼分享
這篇文章主要為大家詳細介紹了如何錄音C語言實現(xiàn)一個簡易的通訊錄(靜態(tài)版本),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-10-10求斐波那契(Fibonacci)數(shù)列通項的七種實現(xiàn)方法
本篇文章是對求斐波那契(Fibonacci)數(shù)列通項的七種實現(xiàn)方法進行了詳細的分析介紹,需要的朋友參考下2013-05-05