菱形继承和虚继承、对象模型和虚基表
1.菱形繼承(鉆石繼承):兩個子類繼承同一父類,而又有子類同時繼承這兩個子類。例如B,C兩個類同時繼承A,但是又有一個D類同時繼承B,C類。
2.菱形繼承的對象模型
class A { public:int _a; };class B :public A { public:int _b; }; class C :public A { public:int _c; }; class D :public B,public C { public:int _d; };上述的代碼對應(yīng)的菱形繼承的對象模型如下圖所示
3.菱形繼承所帶來的問題
(1)由上圖的對象模型可以看出,D的對象中有兩份A成員,造成了數(shù)據(jù)的冗余。使用sizeof去驗證,可以發(fā)現(xiàn)d的大小為20個字節(jié)。
(2)會造成基類子對象重復(fù),即二義性。造成訪問基類的成員不明確。
4.解決菱形繼承所帶來的問題
(1)要解決二義性很簡單,可以顯示的指定訪問哪個父類的成員,但是這個還是不能從根本上解決這個問題。如:
(2)要從本質(zhì)上解決上述問題,需要采用虛繼承:虛繼承是一種機(jī)制,類通過虛繼承指出它希望共享虛基類的狀態(tài)。對給定的虛基類,無論該類在派生層次中作為虛基類出現(xiàn)多少次,只繼承一個共享的基類子對象,共享基類子對象稱為虛基類。虛基類用virtual聲明繼承關(guān)系就行了。這樣一來,D就只有A的一份拷貝。
如:
采用虛繼承和顯示指定訪問父類成員,對對象所產(chǎn)生的的影響有什么不同呢?顯示指定訪問并不能起到一改全改的作用,那么就會造成一個對象d有兩個不相同的成員_a,明顯是不符合常規(guī)的。
5.深入理解虛繼承
現(xiàn)在來了解多出來的四個字節(jié)究竟是什么?首先我們通過調(diào)試——>內(nèi)存查看對象d的地址的數(shù)據(jù),可以看到如下現(xiàn)象:
(1)(2)中存放的數(shù)據(jù)究竟是用來表示什么的呢?再將d._a分別賦值成為0和4,通過內(nèi)存窗口觀察d的地址的數(shù)據(jù)
由圖可以看到末排的地址存放的數(shù)據(jù)剛好是d._a的值的大小,那么多出來的第一排和第三排的數(shù)據(jù)看起來似乎是兩個地址,輸入地址查看一下數(shù)據(jù)
明顯可以看到兩個地址存放的數(shù)據(jù)是每個對象相對于基類的成員的偏移量,對應(yīng)的每個地址所代表的意義如下:
這樣也就可以解釋為什么d的大小為24個字節(jié)因為虛繼承引入了間接性指針
6.在虛繼承的前提下,重新建立對象模型
7.在菱形繼承且為虛繼承的前提下,討論虛基表為什么首先不存偏移量,而是在存偏移量之前預(yù)留了一個0x0000 0000的位置呢?
(1)首先,設(shè)置一個菱形繼承,且為虛繼承,每個子類既重寫了父類的虛函數(shù),還擁有自己的虛函數(shù)
用菱形繼承的模型圖來表示關(guān)系就是:
通過實(shí)例化出對象d,并查看內(nèi)存可以看到對象布局,可以看到有五個類似地址的部分,一一通過內(nèi)存窗口查看內(nèi)容,發(fā)現(xiàn)三張為虛表(存放虛函數(shù)),兩張為虛基表(存放偏移量的),在下圖中用不同的顏色標(biāo)注出來了:
通過內(nèi)存窗口查看各個虛基表的地址:
可以看到虛基表的開始預(yù)留一個位置是用來存放虛基表和虛表的地址之差的。
內(nèi)存分布模型:
那么可以看到實(shí)例化出來的對象d的對象模型為:
至于虛表存放的虛函數(shù)順序是怎么存放的:
http://blog.csdn.net/skyroben/article/details/68192874
總結(jié)
以上是生活随笔為你收集整理的菱形继承和虚继承、对象模型和虚基表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 富瀚微的芯片哪里代工 带你了解
- 下一篇: 京东白条还了还能借出来吗