c++為了實現執行時的多型,引入了虛函式的概念。為了實現執行時多型的,其底層一般採用虛函式表來實現對虛函式的動態繫結,進而在基類物件的引用或指標在呼叫同名的虛函式時可以根據引用或指標指向物件的實際型別呼叫相應的函式。當類的繼承關係中沒有使用多繼承時,物件的虛函式表結構還相對簡單;然而繼承**現多整合時,問題就變得複雜起來了。
有如下的乙個例子:
class a
virtual void fun1()
cout<>32) << " 低4b:" << (unsigned int)temp << endl;
}}int main()
sizeof a:16
sizeof base1:16
sizeof base2:16
sizeof derive:40
整體:93869941914944 高4b:21855 低4b:3431660864
整體:93866510254081 高4b:21855 低4b:1
虛表位址》0x555fcc8afd40
第1個虛函式位址 :0xcc6aef42,->a::fun1(
)
對於a,占有16b記憶體,虛函式表指標佔8b,資料成員a實際只佔4b,由於記憶體對齊,所以sizeof a是16 b。對於base1或base2.輸出結果如下:
sizeof base1:16
整體:94892606594304 高4b:22093 低4b:3894123776
整體:8589934593 高4b:2 低4b:1
虛表位址》0x564de81b9d00
第1個虛函式位址 :0xe7fb9032,->a::fun1(
)第2個虛函式位址 :0xe7fb90a6,->base1::func1
第3個虛函式位址 :0xe7fb90de,->base1::func2
為什麼base1的長度也是16 b呢?是因為來自a的a和b1 成員分別使用了高4b和低4 b。
這個例子中還出現了菱形繼承的情況:base1和base2繼承自a,而derive又同時繼承自base1和base2。同時每個類中都帶有虛函式。那這時候derive是怎麼處理自有的虛函式和繼承來的虛函式的呢?它的虛函式表又是什麼樣的結構呢?先輸出其記憶體內容。
cout << "sizeof derive:" << sizeof(derive) << endl;
derive d(4);
ull * vtable =(ull *) (*(ull*)(&d));
printmem(d);
sizeof derive:40
整體:94560403680304 高4b:22016 低4b:2403691568
整體:12884901889 高4b:3 低4b:1
整體:94560403680352 高4b:22016 低4b:2403691616
整體:8589934593 高4b:2 低4b:1
整體:140733193388036 高4b:32767 低4b:4
可以看到, derive佔40b記憶體,第乙個8b是乙個虛函式表位址,第二個8b分別是a的a成員和base2的b2成員,第三個8b又是乙個虛函式表位址,第四個8b是又乙個a的a成員和base1的b1成員。最後乙個8b,低4b是derive的c3成員,高四b未使用。
接下來去輸出其兩個虛函式表:
虛表位址》0x564544793c30
第1個虛函式位址 :0x44593286,->a::fun1(
)第2個虛函式位址 :0x44593476,->derive::func1
第3個虛函式位址 :0x445933de,->base2::func2
第4個虛函式位址 :0x445934b4,->derive::func3
虛表位址》0x564544793c60
第1個虛函式位址 :0x44593286,->a::fun1(
)第2個虛函式位址 :0x445934ad,->derive::func1
第3個虛函式位址 :0x44593332,->base1::func2
這是還沒有使用虛繼承的情況,當使用虛繼承是又會是什麼樣呢?
class a
virtual void fun1()
{cout << "a::fun1()" 《這時輸出derive物件的記憶體及虛函式表:
sizeof derive:48
整體:94345236515712 高4b:21966 低4b:1984891776
整體:94343251623939 高4b:21966 低4b:3
整體:94345236515760 高4b:21966 低4b:1984891824
整體:17179869186 高4b:4 低4b:2
整體:94345236515800 高4b:21966 低4b:1984891864
整體:94343251623937 高4b:21966 低4b:1
可以看到此時derive佔48b,第乙個8b是乙個虛函式表指標,第二個8b的低4b是base2的b2成員,高4b未使用,第三個8b又是乙個虛函式表指標,第四個8b低4b是base1的b1成員高4b是derive的c3成員,第五個8b又是乙個虛函式指標,最後乙個8b低四位是a的a成員,高4b未使用。注意這裡只出現了乙個a的副本,符合虛繼承的情況。下面是三個虛函式表的內容。
虛表位址》0x5646fc2fcb80
第1個虛函式位址 :0xfc0fc568,->derive::func1
第2個虛函式位址 :0xfc0fc492,->base2::func2
第3個虛函式位址 :0xfc0fc5a6,->derive::func3
虛表位址》0x5646fc2fcbb0
第1個虛函式位址 :0xfc0fc59f,->derive::func1
第2個虛函式位址 :0xfc0fc3d4,->base1::func2
虛表位址》0x5646fc2fcbd8
第1個虛函式位址 :0xfc0fc316,->a::fun1(
)
但是這裡出現了乙個我暫時無法解釋的現象,在不同的虛函式表對應的同乙個虛函式的位址不一樣。
環境:ubuntu18.04 lts、g++ 5.5.0 。
C 虛函式多繼承的虛函式表指標的測試
c 虛函式多繼承的虛函式表指標的測試 看了很多關於虛函式的實現機制,現在來動手驗證一下吧 include using namespace std class a class b class cc public a public b int main 執行結果 12 cc 0012ff74 pa 00...
單繼承和多繼承的虛函式表
前面兩篇關於多型的部落格已經詳細介紹了多型的基礎知識點和多型的底層實現原理,下面將主要介紹一下單繼承和多繼承的虛函式表 首先來看一段 class base virtual void func2 private int b 1 class derive public base virtual void...
單繼承與多繼承中的虛函式表和虛函式指標
編譯環境 vs 2013 首先,我們了解一下何為單繼承,何為多繼承?單繼承 乙個子類只有乙個直接父類。多繼承 乙個子類有兩個或多個直接父類。單繼承中的虛函式表分析 示例程式 include using namespace std typedef void func class base virtua...