首先要說一下多繼承,虛基類和虛繼承都是在多繼承的一種情況下存在的內容。
多繼承是子類繼承自多個父類的繼承方式。
但是在多繼承的過程中,存在這樣一種情況,一個基類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.虛繼承只能用來解決這一個問題嗎,還可以應用在哪些場景呢?