日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

菱形继承和虚继承、对象模型和虚基表

發布時間:2025/3/8 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 菱形继承和虚继承、对象模型和虚基表 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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; };

上述的代碼對應的菱形繼承的對象模型如下圖所示

3.菱形繼承所帶來的問題
(1)由上圖的對象模型可以看出,D的對象中有兩份A成員,造成了數據的冗余。使用sizeof去驗證,可以發現d的大小為20個字節。

(2)會造成基類子對象重復,即二義性。造成訪問基類的成員不明確。

4.解決菱形繼承所帶來的問題
(1)要解決二義性很簡單,可以顯示的指定訪問哪個父類的成員,但是這個還是不能從根本上解決這個問題。如:

D d; d.B::_a; //d.C::_a; //上述兩種方法取其一就可以規避這個問題

(2)要從本質上解決上述問題,需要采用虛繼承:虛繼承是一種機制,類通過虛繼承指出它希望共享虛基類的狀態。對給定的虛基類,無論該類在派生層次中作為虛基類出現多少次,只繼承一個共享的基類子對象,共享基類子對象稱為虛基類。虛基類用virtual聲明繼承關系就行了。這樣一來,D就只有A的一份拷貝。
如:

class A { public:int _a; };class B : virtual public A { public:int _b; }; class C :virtual public A { public:int _c; }; class D :public B,public C { public:int _d; };

采用虛繼承和顯示指定訪問父類成員,對對象所產生的的影響有什么不同呢?顯示指定訪問并不能起到一改全改的作用,那么就會造成一個對象d有兩個不相同的成員_a,明顯是不符合常規的。

1. 顯然我們不用顯示的指定訪問哪個父類的成員,但是可以清晰看到d的大小并不是期望中的16,而是24個字節,這是為什么呢?


5.深入理解虛繼承
現在來了解多出來的四個字節究竟是什么?首先我們通過調試——>內存查看對象d的地址的數據,可以看到如下現象:


(1)(2)中存放的數據究竟是用來表示什么的呢?再將d._a分別賦值成為0和4,通過內存窗口觀察d的地址的數據

由圖可以看到末排的地址存放的數據剛好是d._a的值的大小,那么多出來的第一排和第三排的數據看起來似乎是兩個地址,輸入地址查看一下數據

明顯可以看到兩個地址存放的數據是每個對象相對于基類的成員的偏移量,對應的每個地址所代表的意義如下:

這樣也就可以解釋為什么d的大小為24個字節因為虛繼承引入了間接性指針
6.在虛繼承的前提下,重新建立對象模型

7.在菱形繼承且為虛繼承的前提下,討論虛基表為什么首先不存偏移量,而是在存偏移量之前預留了一個0x0000 0000的位置呢?
(1)首先,設置一個菱形繼承,且為虛繼承,每個子類既重寫了父類的虛函數,還擁有自己的虛函數

class A { public:virtual void f1(){cout << "A::f1()" << endl;cout << endl;}virtual void f2(){cout << "A::f2()" << endl;cout << endl;}int _a; };class B :virtual public A { public:virtual void f1(){cout << "B::f1()" << endl;cout << endl;}virtual void f3(){cout << "B::f3()" << endl;cout << endl;}int _b; }; class C :virtual public A { public:virtual void f1(){cout << "C::f1()" << endl;cout << endl;}virtual void f4(){cout << "C::f4()" << endl;cout << endl;}int _c; };class D :public B,public C { public:virtual void f1(){cout << "D::f1()" << endl;cout << endl;}virtual void f5(){cout << "D::f5()" << endl;cout << endl;}int _d; };

用菱形繼承的模型圖來表示關系就是:

通過實例化出對象d,并查看內存可以看到對象布局,可以看到有五個類似地址的部分,一一通過內存窗口查看內容,發現三張為虛表(存放虛函數),兩張為虛基表(存放偏移量的),在下圖中用不同的顏色標注出來了:

通過內存窗口查看各個虛基表的地址:

可以看到虛基表的開始預留一個位置是用來存放虛基表和虛表的地址之差的。
內存分布模型:

那么可以看到實例化出來的對象d的對象模型為:

至于虛表存放的虛函數順序是怎么存放的:
http://blog.csdn.net/skyroben/article/details/68192874

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的菱形继承和虚继承、对象模型和虚基表的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。