菱形繼承,虛繼承

audience_fzn發表於2018-08-06

一、單繼承和多繼承

  • 單繼承:一個子類只有一個直接父類時,稱這個繼承為單繼承
  • 多繼承:一個子類有倆個或以上的直接父類時稱這個繼承關係為多繼承
  • 單繼承:

可以有多個父類,但是隻能由一個直接父類

  • 多繼承:

二、菱形繼承: 

菱形繼承的例子:

class person
{
public:
	string _name;
};

class student : public person
{
protected:
	int _num;
};

class teather :public person
{
protected:
	int _id;
};

class Assistant :public student, public teather
{
protected:
	string _majorCourse;
};

void Test()
{
	Assistant a;
	//a._name = "xxx";//對_name的訪問不明確,要指定他們在哪個類裡
	a.student::_name = "xxx";
	a.teather::_name = "yyy";
}

這個編譯是可以通過的,但是我們發現這樣的話,一個人就具有了倆個名字,這樣的菱形繼承是被人詬病的

這據說明我們的菱形繼承存在二義性和資料冗餘問題

三、虛繼承(virtual)——解決菱形繼承的二義性和資料冗餘的問題

  • 虛繼承解決了在菱形繼承體系裡面子類物件包含多份父類物件的資料冗餘&浪費空間的問題
  • 虛繼承體系看起來好複雜,在實際應用中我們通常不會定義這麼複雜的繼承體系。一般不到萬不得已都不要定義菱形結構的虛繼承體系,因為使用虛繼承解決資料冗餘問題的同時也帶來了效能上的損耗

class A
{
public:
	int _a;
};

class B : virtual public A
{
public:
	int _b;
};

class C :virtual public A
{
public:
	int _c;
};

class D:public B, public C
{
public:
	int _d;
};

void Test()
{
	D dd;
	cout << sizeof(dd) << endl;
	dd.B::_a = 1;
	dd._b = 3;
	dd.C::_a = 2;
	dd._c = 4;
	dd._d = 5;

}

執行程式碼,看其監視視窗

 

我們發現只要更改一個值,所有的_a的值都改變了,為什麼呢?虛繼承到底做了什麼?

虛繼承之所以能解決二義性和資料冗餘的問題,他們在原本需要存放資料的地方存放了一個地址,而真正的“_a”資料放在物件的最底下,而我們只要通過這個地址裡的內容——偏移量,就能找到我們實際要訪問的變數“_a”;

 

注:

友元關係不能繼承,也就是說友元不能訪問子類私有和保護成員

父類定義了static成員,則整個繼承體系裡面只要一個這樣的成員,無論子類生出多少個子類,都只有一個static成員例項

 

相關文章