C++ 虛繼承 虛基類 多繼承 詳細解讀

首先要說一下多繼承,虛基類和虛繼承都是在多繼承的一種情況下存在的內容。

多繼承是子類繼承自多個父類的繼承方式。

但是在多繼承的過程中,存在這樣一種情況,一個基類A分別被中間基類B、C繼承,然後D又繼承了B、C,此時就出現了問題

?如果子類D使用父類B或者父類C獨有的成員變量,這時沒有問題。但是如果D使用的是A的成員變量,編譯器就不知道使用的B繼承自A的還是C繼承自A的,產生了一個語義模糊的概念(aimbiguous的錯誤)。

注:成員函數是可以被多繼承的而不產生上述問題,因爲函數是在編譯階段就已經生成了內存的,不需要像成員變量一樣之後還會有更改。

這時候,就一定要引入虛繼承的概念來避語義的模糊,讓B、C類虛繼承自A,那麼A的成員變量在D中只會保留一份,所以取消了語義模糊衝突(具體在內存中爲什麼會這樣我還得在思考思考)。

意味着虛繼承是一種簡介繼承的模式,對虛繼承的子類本身沒有問題,只對該子類的子孫(具體是再往下繼承一層還是多層需要實驗)有影響。

#include <iostream>

using namespace std;

class A {
protected:
    int A_a;
};

class B : public A {
protected:
    int B_b;
};

class C : public A {
protected:
    int C_c;
};

class D : public B, public C {
protected:
    int D_d;
public:

    // 此時就出現了問題,編譯器不知道調用的a是繼承自B的還是繼承自C的,所以會產生模棱兩可的情況即ambiguous,此時就要引出超級無敵的虛繼承!!!
    //void A_func () {A_a = 1;}

    void B_func () {B_b = 2;}
    void C_func () {C_c = 3;}
    void D_func () {D_d = 4;}
};


////////////////////////////////////////////////////////////////////////////////////
class I {
protected:
    int i;
public:
    void setI (int i) {
        this->i = i;
    }

    int retI () {
        return i;
    }

    void specialA () {
        cout << "funcA " << endl;
    }
};

class J : virtual public I {
protected:
    int j;
    public:

        void setI (int i) {
            this->i = i;
        }

    int retI () {
        return i;
    }
};

class K : virtual public I {
protected:
    int k;
public:
    int retI () {
        return i;
    }
};
class H : public J, public K {
protected:
    int H;
public:
    void funcA () {i = 1;}
    void funcB () {j = 2;}

    void funcC () {k = 3;}

    void funcD () {H = 4;}

    const void SetI (int i) {this->i = i;}
    const int  retI () {return i;}
};
////////////////////////////////////////////////////////////////////////////////////


int main ()
{
    // 在菱形繼承&虛繼承中,如果一箇中間類改變了虛基類中的一個成員變量繼承下來的值,那麼這個虛基類的成員變量的值是否被改變呢,那麼這個中間類的兄弟類的相同成員變量的值被改變了嗎
    I i;
    J j;
    K k;
    H h;

    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;
    cout << "可以看到此時所有的I都是未初始化的狀態,但是所指向的內存卻不同" << endl;
    i.setI (1);
    cout << "將I中的i設置爲1之後:" << endl;
    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;
    j.setI (2);
    cout << "將J中的i設置爲2之後:" << endl;
    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;
    k.setI (3);
    cout << "將K中的i設置爲3之後:" << endl;
    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;
    h.setI (4);
    cout << "將H中的i設置爲4之後:" << endl;
    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;

    h.specialA ();

    // 由此可見,虛繼承中不同的類並不是共享內存的,應該是在類似於虛函數表的地方表示虛繼承前後的變量

    return 0;
}

ps:問題?1.虛繼承在一開始出現的時候就是爲了解決上述問題的嗎?

2.虛繼承只能用來解決這一個問題嗎,還可以應用在哪些場景呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章