" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

2.菱形繼承所帶來的問題

先理解一段簡單的代碼:

/*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; // 報錯,_a不明確
        d.B::_a = 3;
        d.C::_a = 8;
        return 0;
}

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

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

3.虛繼承的解決方案

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

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類對象中的A類對象不再存儲成員變量,而是存儲一個未知值,這個位置本應(yīng)該存儲A類對象的成員變量,但是A類的成員變量卻跑到了B類對象的最后。如此類推,如果再有一個C類虛繼承自A類,那么C類對象模型也應(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;
    /*都不報錯了,他們操作的都是同一個_a*/
    d._a = 1;
    d.B::_a = 3;
    d.C::_a = 8;
    return 0;
}

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

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

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

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

3.1虛基表

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

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

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

4.繼承與組合

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

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

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

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

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

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

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

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

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

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

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

相關(guān)文章

  • C語言解決螺旋矩陣算法問題的代碼示例

    C語言解決螺旋矩陣算法問題的代碼示例

    這篇文章主要介紹了C語言解決螺旋矩陣算法問題的代碼示例,螺旋矩陣中的數(shù)字由第一行開始到右邊不斷變大,向下變大,向左變大,向上變大,如此循環(huán)...需要的朋友可以參考下
    2016-04-04
  • C++之編寫高效Makefile文件最佳方法

    C++之編寫高效Makefile文件最佳方法

    在軟件開發(fā)過程中,Makefile是一個非常重要的工具,它可以幫助我們自動化構(gòu)建、編譯、測試和部署,然而,編寫高效的Makefile文件并不是一件容易的事情。在本文中,我們將討論如何編寫高效的Makefile文件,以提高開發(fā)效率和產(chǎn)品質(zhì)量,需要的朋友可以參考下
    2023-05-05
  • C++語言數(shù)據(jù)結(jié)構(gòu) 串的基本操作實(shí)例代碼

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

    這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu) 串的基本操作實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • VC編程控件類HTControl之CHTGDIManager GDI資源管理類用法解析

    VC編程控件類HTControl之CHTGDIManager GDI資源管理類用法解析

    這篇文章主要介紹了VC編程控件類HTControl之CHTGDIManager GDI資源管理類用法解析,需要的朋友可以參考下
    2014-08-08
  • C語言實(shí)現(xiàn)3個數(shù)從小到大排序/輸出的方法示例

    C語言實(shí)現(xiàn)3個數(shù)從小到大排序/輸出的方法示例

    這篇文章主要給大家介紹了關(guān)于如何利用C語言實(shí)現(xiàn)3個數(shù)從小到大排序/輸出的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用C語言具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • C語言動態(tài)內(nèi)存分配圖文講解

    C語言動態(tài)內(nèi)存分配圖文講解

    給數(shù)組分配多大的空間?你是否和初學(xué)C時的我一樣,有過這樣的疑問。這一期就來聊一聊動態(tài)內(nèi)存的分配,讀完這篇文章,你可能對內(nèi)存的分配有一個更好的理解
    2023-01-01
  • C++編程模板匹配超詳細(xì)的識別手寫數(shù)字實(shí)現(xiàn)示例

    C++編程模板匹配超詳細(xì)的識別手寫數(shù)字實(shí)現(xiàn)示例

    大家好!本篇文章是關(guān)于手寫數(shù)字識別的,接下來我將在這里記錄我的手寫數(shù)字識別的從零到有,我在這里把我自己的寫代碼過程發(fā)出來,希望能幫到和我一樣努力求知的人
    2021-10-10
  • C語言靜態(tài)動態(tài)兩版本通訊錄實(shí)戰(zhàn)源碼

    C語言靜態(tài)動態(tài)兩版本通訊錄實(shí)戰(zhàn)源碼

    這篇文章主要為大家?guī)砹薈語言實(shí)現(xiàn)靜態(tài)動態(tài)兩版本的通訊錄實(shí)戰(zhàn)源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • C++設(shè)計模式之簡單工廠模式的實(shí)現(xiàn)示例

    C++設(shè)計模式之簡單工廠模式的實(shí)現(xiàn)示例

    這篇文章主要給大家介紹了關(guān)于C++設(shè)計模式之簡單工廠模式的相關(guān)資料,簡單工廠模式,主要用于創(chuàng)建對象,添加類時,不會影響以前的系統(tǒng)代碼,需要的朋友可以參考下
    2021-06-06
  • c語言通過棧判斷括號匹配是否配對

    c語言通過棧判斷括號匹配是否配對

    前面實(shí)現(xiàn)了棧的基本數(shù)據(jù)結(jié)構(gòu),這里來做一個聯(lián)系,用棧來解決一道比較常見的算法題,就是括號配對是否滿足規(guī)則,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2023-09-09

最新評論