C 虛繼承 一 vtordisp欄位

2021-07-10 14:09:36 字數 1959 閱讀 7705

關於vtordisp知多少?

首先從產生「vtordisp」問題的那個例子開始。

class base

};

class der:virtual public base

virtual void fun(){}

};

der物件模型如下:

1>  class der    size(20):

1>      +---

1>   0    | 

1>   4    | der

1>      +---

1>  8    | (vtordisp for vbase base)

1>      +--- (virtual base base)

1>  12    | 

1>  16    | base

1>      +---

1>  

1>  der::$vbtable@:

1>   0    | 0

1>   1    | 12 (derd(der+0)base)

1>  

1>  der::$vftable@:

1>      | -12

1>   0    | &(vtordisp) der::fun

1>  

1>  der::fun this adjustor: 12

1>  

1>  vbi:       class  offset o.vbptr  o.vbte fvtordisp

1>              base      12       0       4 1

我們發現物件的8位元組偏移處,使用了4個位元組儲存了虛基類base的vtordisp。在我的前一篇部落格內,我們並未涉及這個內容。首先,我從查閱一下vtordisp的msdn的解釋

。msdn給出的解釋是:虛繼承中派生類重寫了基類的虛函式,並且在建構函式或者析構函式中使用指向基類的指標呼叫了該函式,編譯器會為虛基類新增vtordisp域

然而,經過vs2010的測試,我們發現上述示例**便會產生vtordisp欄位!條件是。

1. 派生類重寫了虛基類的虛函式。

2. 派生類定義了建構函式或者析構函式。

這兩個條件缺一不可,這個結論與這裡的描述

是一致的。

但是,到目前為止,我們只是確定了vtordisp的產生條件而已。它究竟為什麼存在物件的模型中,物件如何使用它,我們仍一無所知!

按照前邊的資料內容,這個欄位和編譯選項/vd相關。/vd被稱為構造置換(具體什麼意思,我也不太清楚,慚愧!),它所解決的問題是:由於對類的虛擬基的置換與對其派生類的置換之間有差異,可能會向虛函式傳遞錯誤的this 指標。該解決方案向類的各個虛擬基提供稱作vtordisp 欄位的單個構造置換調整。但是如何構造產生錯誤this指標的測試用例,請恕作者才疏學淺不能給出,也希望看到此文的大牛們給出測試用例。

另外,編譯器還提供了預編譯命令關閉vtordisp欄位的產生。

#pragma vtordisp()

在我們剛才**的前段關閉該字段的產生,事實證明也不會產生預期的錯誤,這的確匪夷所思,園子內另一篇部落格下

中找到了另外一些線索。按照它的描述,這個字段一直儲存為0。為了證明該猜測,我們用der構造乙個物件der,並檢視該物件的記憶體內容。

參考物件模型,該物件vtordisp的位置的確儲存的是0。

曾經我遇到過乙個虛擬繼承的例項,在物件的初始化過程中會修改vtordisp欄位,但是每次在初始化結束前都會把vtordisp減去乙個常量使得它的最終結果為0。而且沒有出現任何訪問該字段的彙編指令!(既然不訪問,為何浪費指令設定它的值呢?)因此,這也讓我懷疑編譯器設計vtordisp的合理性。

無論如何,我們發現對編譯器產生的vtordisp欄位了解的是太少了。單純依靠**動作猜測該欄位存在的含義可行性十分有限,希望對此內容清楚的園友能給出合理的解釋。

C 虛繼承和虛繼承

虛繼承是在多繼承中為了解決衝突而技術。學術一點來說,是指乙個指定的基類,在繼承體系結構中,將其成員資料例項共享給也從這個基類直接或間接派生的其他類。虛繼承非常有用,可以避免多繼承的歧義和多重拷貝。考慮有如下繼承結構。b和c繼承a,d多繼承b c,我們看以下 class a class b publi...

虛函式 虛繼承 C

關於虛表,我們就要用到乙個關鍵字 virtual,可以修飾函式,也可以修飾類。類的成員函式被virtual修飾之後,就成為了虛函式 修飾類,主要是虛繼承。在此之前,我們首先要了解乙個概念 物件模型,也就是說,乙個基類形成之後,裡面的成員是怎麼存放的,當派生類繼承基類之後,派生類的成員是怎麼存放的。我...

C 多重繼承 虛繼承

c 中的多繼承,建構函式處理並沒有問題,物件構造的時候按照繼承中宣告的順序呼叫多個父類的建構函式,析構函式同樣遵守單繼承中的原則。二意性問題 如果多基類中存在同名成員,會產生二意性的問題 比如,root1類中宣告doany 介面,root2類中也宣告了doany 介面,child多承繼root1和r...