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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

虚拟继承

發(fā)布時間:2024/2/28 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 虚拟继承 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.為什么需要虛繼承

如下圖所示如果訪問Der::Fun or Der::m_nValue就會帶來二義性,無法確定是調(diào)用Base1的還是Base2的,所以為了解決多重繼承情況下成員訪問的二義性,引入了虛繼承機(jī)制。
一般繼承:

虛繼承:

2.虛繼承實(shí)現(xiàn)

在虛繼承下,Der通過共享虛基類SuperBase來避免二義性,在Base1,Base2中分別保存虛基類指針,Der繼承Base1,Base2,包含Base1, Base2的虛基類指針,并指向同一塊內(nèi)存區(qū),這樣Der便可以間接存取虛基類的成員,如下圖所示:

3.不同編譯器實(shí)現(xiàn)方式

不同編譯器對間接存取的方法不同,以下以GCC和VC為例,均采用以下代碼進(jìn)行實(shí)驗(yàn):

view plaincopy to clipboardprint?

  • class?SuperBase??
  • {??
  • public:??
  • ????int?m_nValue;??
  • ????void?Fun(){}??
  • ????virtual?~SuperBase(){}??
  • };??
  • class?Base1:??virtual?public?SuperBase??
  • {??
  • public:??
  • virtual?~?Base1(){}??
  • };??
  • class?Base2:??virtual?public?SuperBase??
  • {??
  • public:??
  • virtual?~?Base2(){}??
  • };??
  • class?Der:public?Base1,?public?Base2??
  • {??
  • public:??
  • virtual?~?Der(){}??
  • };??
  • 1) GCC中結(jié)果為8, 12, 12, 16

    解析:sizeof(SuperBase) = sizeof(int) + 虛函數(shù)表指針

    sizeof(Base1) = sizeof(Base2) = sizeof(int) + 虛函數(shù)指針 + 虛基類指針

    sizeof(Der) = sizeof(int) + Base1中虛基類指針 + Base2虛基類指針 + 虛函數(shù)指針

    GCC共享虛函數(shù)表指針,也就是說父類如果已經(jīng)有虛函數(shù)表指針,那么子類中共享父類的虛函數(shù)表指針空間,不在占用額外的空間,這一點(diǎn)與VC不同,VC在虛繼承情況下,不共享父類虛函數(shù)表指針,詳見如下。

    2)VC中結(jié)果為:8, 16, 16, 24

    解析:sizeof(SuperBase) = sizeof(int) + 虛函數(shù)表指針

    sizeof(Base1) = sizeof(Base2) = sizeof(int) + SuperBase虛函數(shù)指針 + 虛基類指針 + 自身虛函數(shù)指針

    sizeof(Der) = sizeof(int) + Base1中虛基類指針 + Base2中虛基類指針 + Base1虛函數(shù)指針 + Base2虛函數(shù)指針 + 自身虛函數(shù)指針

    如果去掉虛繼承,結(jié)果將和GCC結(jié)果一樣,A,B,C都是8,D為16,原因就是VC的編譯器對于非虛繼承,父類和子類是共享虛函數(shù)表指針的。

    ?

    繼承中的內(nèi)存布局

    1. 虛函數(shù)指針(vptr)放最前,之后放變量。
    2. 多個父類排著放,再放子類
    3. 子類的覆蓋的虛函數(shù)將所有祖先的同名虛函數(shù)都覆蓋。
    4. 子類其它的虛函數(shù)指針放在第一個父類的虛函數(shù)表里。
    5. 虛擬繼承的情況只需要在鉆石繼承中有必要使用(避免二義性),子類中最先的祖先放最后。

    多說不如舉例,看下面轉(zhuǎn)的文章。

    本文章轉(zhuǎn)自:http://blog.csdn.net/randyjiawenjie/article/details/6693337

    分為四種情況:
    1.單繼承

    2.多繼承(不含鉆石繼承)

    3.非虛繼承的鉆石繼承

    4.虛繼承的鉆石繼承

    注:下面所有類中的函數(shù)都是虛函數(shù)。

    1.單繼承

    單繼承體系如下:

    GrandChild對象的內(nèi)存布局:

    可見以下幾個方面:

    1)虛函數(shù)表在最前面的位置。

    2)成員變量根據(jù)其繼承和聲明順序依次放在后面。

    3)在單一的繼承中,被overwrite的虛函數(shù)在虛函數(shù)表中得到了更新。

    2.多繼承

    多繼承的體系如下:

    Derive對象的內(nèi)存布局如下:

    我們可以看到:

    1) 每個父類都有自己的虛表。

    2) 子類的成員函數(shù)被放到了第一個父類的表中。

    3) 內(nèi)存布局中,其父類布局依次按聲明順序排列。

    4) 每個父類的虛表中的f()函數(shù)都被overwrite成了子類的f()。這樣做就是為了解決不同的父類類型的指針指向同一個子類實(shí)例,而能夠調(diào)用到實(shí)際的函數(shù)。

    出現(xiàn)鉆石繼承的虛繼承的時候,虛基類在子類中只有一份。

    出現(xiàn)鉆石繼承的非虛繼承的時候,虛基類在每個子類中都有一份。

    3.非虛繼承的鉆石繼承

    繼承體系如下:

    D的內(nèi)存布局如下:

    紅色的部分就是重復(fù)的部分,就會造成二義性

    4.虛繼承的鉆石繼承

    (虛繼承就是解決鉆石繼承問題的,如果不存在鉆石繼承,就不用虛繼承)

    繼承體系如下:(紅色專門標(biāo)準(zhǔn)虛繼承)


    D的內(nèi)存布局如下:

    可以看出,少了重合的部分。但是,代價是增加了一個虛函數(shù)指針。

    總結(jié)

    以上是生活随笔為你收集整理的虚拟继承的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。