" />

最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++菱形繼承和虛繼承的實(shí)現(xiàn)

 更新時(shí)間:2023年06月01日 11:23:25   作者:小龍向錢(qián)進(jìn)  
本文主要介紹了C++菱形繼承和虛繼承的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

菱形繼承和虛繼承本身就是一個(gè)"bug",甚至在C++程序員當(dāng)中有"誰(shuí)用誰(shuí)尚阿比"的說(shuō)法。至于為什么要談菱形繼承和虛繼承,那就是因?yàn)槊嬖嚬僖獑?wèn)。

1.什么是菱形繼承和虛繼承

C++作為"第一個(gè)吃螃蟹的人",勇敢地設(shè)計(jì)出了多繼承的語(yǔ)法,多繼承出現(xiàn)之后,由于一些頂尖程序員的腦洞非常大,就發(fā)現(xiàn)了菱形繼承所帶來(lái)數(shù)據(jù)冗余和二義性的問(wèn)題,C++標(biāo)準(zhǔn)委員會(huì)為了解決這個(gè)問(wèn)題,就設(shè)計(jì)出了虛繼承。從此之后,后面"抄作業(yè)的人"就沒(méi)有多繼承的語(yǔ)法,例如java。

2.菱形繼承所帶來(lái)的問(wèn)題

先理解一段簡(jiǎn)單的代碼:

/*B、C繼承自A---D繼承自B、C
 *從而構(gòu)成菱形繼承*/
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;
};
int main()
{
        D d;
        //d._a = 3; // 報(bào)錯(cuò),_a不明確
        d.B::_a = 3;
        d.C::_a = 8;
        return 0;
}

這段代碼的調(diào)試結(jié)果為:

這就很好解釋了二義性的問(wèn)題,因?yàn)樵贒類(lèi)對(duì)象當(dāng)中存在了兩份A類(lèi)對(duì)象,所以要訪問(wèn)D類(lèi)對(duì)象中的A類(lèi)對(duì)象時(shí)必須指明訪問(wèn),否則就會(huì)觸發(fā)二義性。如果在某些應(yīng)用場(chǎng)景中,兩份A類(lèi)對(duì)象確實(shí)是多余的,那么就又觸發(fā)了數(shù)據(jù)冗余問(wèn)題。所以菱形繼承存在數(shù)據(jù)冗余和二義性的問(wèn)題。下面給出這段程序的繼承關(guān)系示意圖和D類(lèi)對(duì)象模型示意圖:

3.虛繼承的解決方案

在介紹如何解決菱形繼承的問(wèn)題之前,先理解一段簡(jiǎn)單的虛擬單繼承的代碼:

class A
{
public:
        int _a = 1;
};
class B : virtual public A // virtual為虛繼承關(guān)鍵字
{
public:
        int _b = 2;
};
int main()
{
        B b;
        return 0;
}

調(diào)試-內(nèi)存窗口截圖如下:

如上圖所示,B類(lèi)對(duì)象中的A類(lèi)對(duì)象不再存儲(chǔ)成員變量,而是存儲(chǔ)一個(gè)未知值,這個(gè)位置本應(yīng)該存儲(chǔ)A類(lèi)對(duì)象的成員變量,但是A類(lèi)的成員變量卻跑到了B類(lèi)對(duì)象的最后。如此類(lèi)推,如果再有一個(gè)C類(lèi)虛繼承自A類(lèi),那么C類(lèi)對(duì)象模型也應(yīng)該像上圖一樣。

解決菱形繼承的方案就是在繼承體系的"腰部"使用虛繼承,以下面這段代碼為例:

class A
{
public:
    int _a = 1;
};
class B : virtual public A
{
public:
    int _b = 2;
};
class C : virtual public A
{
public:
    int _c = 3;
};
class D : public B, public C
{
public:
    int _d = 4;
};
int main()
{
    D d;
    /*都不報(bào)錯(cuò)了,他們操作的都是同一個(gè)_a*/
    d._a = 1;
    d.B::_a = 3;
    d.C::_a = 8;
    return 0;
}

最終調(diào)試的結(jié)果如下:

不要被監(jiān)視窗口所誤導(dǎo),上圖三個(gè)紅色箭頭所指向的_a實(shí)際上是同一個(gè)_a,也就是說(shuō)D類(lèi)對(duì)象的模型當(dāng)中只存在一份A類(lèi)對(duì)象了。

通過(guò)內(nèi)存窗口觀察D類(lèi)對(duì)象的模型:

與之前介紹的一樣,B類(lèi)對(duì)象和C類(lèi)對(duì)象當(dāng)中本該存儲(chǔ)A類(lèi)對(duì)象的位置存儲(chǔ)了一個(gè)隨機(jī)值。實(shí)際上這個(gè)隨機(jī)值是一個(gè)指針,它指向了虛基表。

3.1虛基表

對(duì)于上面的圖片,介紹了所謂的"隨機(jī)值"是指針,指向了一個(gè)名為虛基表的東西,那么再另起一個(gè)內(nèi)存窗口,觀察虛基表的構(gòu)成:

由此可見(jiàn),虛基表存儲(chǔ)的有效內(nèi)容為偏移量,具體的來(lái)說(shuō),當(dāng)某一指針或引用指向D類(lèi)對(duì)象時(shí),需要訪問(wèn)_a時(shí),就需要通過(guò)虛基表當(dāng)中的偏移量來(lái)確定訪問(wèn)目標(biāo)的位置。雖然虛基表的存在增加了幾次指針的運(yùn)算,但是試想以下,如果A類(lèi)對(duì)象足夠大,在菱形繼承體系中不使用虛繼承,那么最終的D類(lèi)對(duì)象就會(huì)有兩份A類(lèi)對(duì)象,并且A類(lèi)對(duì)象是一個(gè)巨大的對(duì)象,那么如果使用了虛繼承,就能將兩份A類(lèi)對(duì)象壓縮成一份A類(lèi)對(duì)象。

所以使用虛繼承,能夠解決菱形繼承帶來(lái)的數(shù)據(jù)冗余和二義性問(wèn)題。最后以一張圖描述D類(lèi)對(duì)象的模型:

4.繼承與組合

組合的類(lèi)設(shè)計(jì)方式是這樣的:

class A
{
public:
        int _a;
};
class B
{
public:
        A a;
};

可以明顯看出與繼承的差別:組合的耦合度更低,繼承的耦合度更高。實(shí)際上在真實(shí)的設(shè)計(jì)環(huán)境當(dāng)中是很忌諱高耦合的,但是某些場(chǎng)景當(dāng)中卻不得不這么做。

繼承是一種is-a的關(guān)系,例如下面這個(gè)例子:

class Person
{};
class Student : public Person
{};

這個(gè)例子所表達(dá)的意思就是Student是Person,即學(xué)生是人。

組合是一種has-a的關(guān)系,例如最開(kāi)頭的那段代碼,表達(dá)的意思就是B類(lèi)對(duì)象當(dāng)中有一個(gè)A類(lèi)對(duì)象。

針對(duì)不同的場(chǎng)景使用不同的復(fù)用手段,當(dāng)條件只允許使用is-a的關(guān)系時(shí)就使用繼承;只允許使用has-a的關(guān)系時(shí)就使用組合;當(dāng)既可以使用繼承又可以使用組合的關(guān)系時(shí)使用組合。

為什么要盡量使用組合關(guān)系?

因?yàn)閷?duì)于繼承來(lái)說(shuō),它相當(dāng)于一種白箱復(fù)用,即箱子里面的內(nèi)容能夠清清楚楚的看到;對(duì)于組合來(lái)說(shuō),它相當(dāng)于一種黑箱復(fù)用,即箱子里面的內(nèi)容大多是不可見(jiàn)的,能夠看見(jiàn)的也僅僅是一部分(例如設(shè)計(jì)類(lèi)時(shí)提供給外部的成員函數(shù))。對(duì)于繼承來(lái)說(shuō),如果基類(lèi)的非private成員發(fā)生了變動(dòng),由于耦合度高的原因,派生類(lèi)也將會(huì)受到影響;對(duì)于組合來(lái)說(shuō),被包含的對(duì)象只有public成員發(fā)生變動(dòng)時(shí),才有可能影響到包含該對(duì)象的對(duì)象。

到此這篇關(guān)于C++菱形繼承和虛繼承的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++菱形繼承和虛繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++語(yǔ)言數(shù)據(jù)結(jié)構(gòu) 串的基本操作實(shí)例代碼

    C++語(yǔ)言數(shù)據(jù)結(jié)構(gòu) 串的基本操作實(shí)例代碼

    這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu) 串的基本操作實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • C++?Boost?Format超詳細(xì)講解

    C++?Boost?Format超詳細(xì)講解

    Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)
    2022-11-11
  • C++輸入流和輸出流 超級(jí)詳細(xì)

    C++輸入流和輸出流 超級(jí)詳細(xì)

    C++ 的開(kāi)發(fā)者認(rèn)為數(shù)據(jù)輸入和輸出的過(guò)程也是數(shù)據(jù)傳輸?shù)倪^(guò)程,數(shù)據(jù)像水一樣從一個(gè)地方流動(dòng)到另一個(gè)地方,所以 C++ 中將此過(guò)程稱(chēng)為“流”,實(shí)現(xiàn)此過(guò)程的類(lèi)稱(chēng)為“流類(lèi)”。下面小編將詳細(xì)介紹這個(gè)話(huà)題,需要的朋友可以參考一下
    2021-09-09
  • 如何高效移除C++關(guān)聯(lián)容器中的元素

    如何高效移除C++關(guān)聯(lián)容器中的元素

    關(guān)聯(lián)容器和順序容器有著很大不同,關(guān)聯(lián)容器中的元素是按照關(guān)鍵字來(lái)保存和訪問(wèn)的,而順序容器中的元素是按它們?cè)谌萜髦械奈恢脕?lái)順序保存和訪問(wèn)的,本文介紹了如何高效移除C++關(guān)聯(lián)容器中的元素的方法,需要的朋友可以參考下
    2025-04-04
  • EasyX繪制透明背景圖的方法詳解

    EasyX繪制透明背景圖的方法詳解

    這篇文章主要為大家詳細(xì)介紹了EasyX繪制透明背景圖的方法,文中的示例代碼講解詳細(xì),對(duì)我們深入了解EasyX有一定的幫助,需要的可以參考一下
    2023-01-01
  • 利用Matlab實(shí)現(xiàn)迭代適應(yīng)點(diǎn)算法

    利用Matlab實(shí)現(xiàn)迭代適應(yīng)點(diǎn)算法

    道格拉斯-普克算法(Douglas–Peucker?algorithm,亦稱(chēng)為拉默-道格拉斯-普克算法、迭代適應(yīng)點(diǎn)算法、分裂與合并算法)是將曲線(xiàn)近似表示為一系列點(diǎn),并減少點(diǎn)的數(shù)量的一種算法。本文將利用Matlab實(shí)現(xiàn)這一算法,需要的可以參考一下
    2022-04-04
  • C++深入刨析muduo中的抽象類(lèi)Poller

    C++深入刨析muduo中的抽象類(lèi)Poller

    muduo網(wǎng)絡(luò)庫(kù)中Poller類(lèi)是一個(gè)抽象類(lèi),用戶(hù)使用PollPoller或者EPollPoller類(lèi),下面跟隨小編一起來(lái)詳細(xì)了解一下
    2022-04-04
  • 基于C++ Lambda表達(dá)式的程序優(yōu)化

    基于C++ Lambda表達(dá)式的程序優(yōu)化

    這篇文章主要介紹了基于C++ Lambda表達(dá)式的程序優(yōu)化的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • C語(yǔ)言中qsort函數(shù)使用及其模擬實(shí)現(xiàn)教程

    C語(yǔ)言中qsort函數(shù)使用及其模擬實(shí)現(xiàn)教程

    C語(yǔ)言中存在著許多排序函數(shù),如我們熟悉的冒泡函數(shù),還有堆排序、歸并排序等等,這些排序函數(shù)的功能給我們帶來(lái)了許多便捷,這篇文章主要介紹了C語(yǔ)言中qsort函數(shù)使用及其模擬實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2025-08-08
  • C\C++實(shí)現(xiàn)讀寫(xiě)二進(jìn)制文件的方法詳解

    C\C++實(shí)現(xiàn)讀寫(xiě)二進(jìn)制文件的方法詳解

    這篇文章主要為大家詳細(xì)介紹了C\C++實(shí)現(xiàn)讀寫(xiě)二進(jìn)制文件的方法,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下
    2023-03-03

最新評(píng)論

朔州市| 兖州市| 呼玛县| 阳信县| 通州市| 佛坪县| 晋宁县| 滨海县| 临桂县| 奈曼旗| 山阳县| 德惠市| 郧西县| 武强县| 江门市| 山丹县| 罗源县| 贵定县| 呼伦贝尔市| 中牟县| 大英县| 麻栗坡县| 莒南县| 罗山县| 龙州县| 东乌| 民县| 日喀则市| 永安市| 唐河县| 安阳市| 新蔡县| 即墨市| 樟树市| 濮阳县| 镇巴县| 正宁县| 余庆县| 工布江达县| 合水县| 小金县|