首先我們已經知道了多繼承和單繼承的物件模型
接下來我們來看乙個複雜的菱形繼承
菱形繼承的多型繼承
然偶我們再將虛表打出來看一看這兩個虛表指標的裡儲存的虛函式各是什麼
我們可以明顯的看到,b裡的虛表和c裡的虛表此時都被d繼承了之後進行了虛函式的重寫,因為d繼承了b和c所以都被d重寫了虛函式此時就打出來的是d的函式
菱形虛繼承的多型模型
classa
public:
int_a;
}; class
b :virtual
publica
public:
int_b;
}; class
c :virtual
publica
public:
int_c;
}; class
d :public
b,publicc
public:
int_d;
}; intmain()
typedef
void
(*func) ();
void
printvtable(
int*vtable)
printf(
"\n"
); }
我們可以看到在d繼承了b和c之後,首先b和c繼承了a的虛表,同時對a進行了虛函式的重寫,但是當有兩個虛函式同時對a的虛函式進行重寫的時候,此時我們其實是不知道a到底是被b還是c重寫的,所以當d繼承了b和c之後也對這個虛函式進行了重寫,最後其實最後d對a的虛函式進行了重寫
列印虛表
模型
我們再來看一種情況
當子類裡不只有重寫的虛函式,還有他自己的沒有被重寫的虛函式這會是怎樣的呢?
1.我們先在b裡加乙個虛函式
classb:
virtual
publica
virtual
void
func2()
public:
int_b;
};然後我們再來看記憶體結構,我們會發現d多了4個位元組,通過看記憶體可以發現,我們的b結構裡多了乙個位址
,我們能確定的是這兩個位址裡肯定有乙個是指向虛基表,那麼另乙個其實就是虛表啦
我們在徐繼承的時候其實b和c都會繼承a的虛表它不會自己去在浪費記憶體再開乙個虛表,但是此前提是他們兩個都沒有多餘的虛函式,一旦當他們兩個任意乙個有了多餘的虛函式,那麼此時他們自己就會在生成乙個虛表,將自己的虛函式放進去,誰有誰開,兩個都有的話兩個都開
然後在兩個同時加虛函式
虛基表接下來我們再來看一下虛基表,我們之前發現虛基表裡其實存的是乙個偏移量,那我們在把記憶體裡的虛基表看一下
其實這兩種虛表是編譯器中最常見的兩種虛表,第一行是判斷此類有無虛表,第二行很明顯是虛繼承偏移量
c 物件模型之菱形繼承
當我們談c 時,我們談些什麼?封裝,繼承,多型。這是c 語言的三大特性,而每次在談到繼承時我們不可避免的要談到乙個很重要的問題 菱形繼承。a.菱形繼承是什麼 如上圖,菱形繼承即多個類繼承了同乙個公共基類,而這些派生類又同時被乙個類繼承。這麼做會引發什麼問題呢,讓我們來看一段 吧 includeusi...
C 菱形繼承記憶體布局的探索
1 2 c 虛繼承下菱形繼承的物件記憶體布局依賴於編譯器。對於vs而言,虛繼承通過虛基類表和虛基類指標 vbptr 實現 對於g 而言,可能會有另一種實現方式。本文基於文章和文章中描述的實驗方法,在linux和g 編譯器環境下,測定了虛繼承菱形繼承生成物件的記憶體布局。執行環境 ubuntu16.0...
C 物件模型5 多繼承下的物件模型
從單繼承可以知道,派生類中只是擴充了基類的虛函式表。如果是多繼承的話,又是如何擴充的?1 每個基類都有自己的虛表。2 子類的成員函式被放到了第乙個基類的表中。3 記憶體布局中,其父類布局依次按宣告順序排列。4 每個基類的虛表中的 print 函式都被 overwrite 成了子類的 print 這樣...