c++ 虛繼承

c++裏面有很大一個重點就是繼承和多態了,今天就先說一下關於繼承的一個小方面。因爲在c++當中的話繼承有
 1.單繼承:一個子類只有一個直接父類時稱爲這個繼承關係爲單繼承
 2.多繼承:一個子類有兩個或以上的父類時稱這個繼承關係爲多繼承
例如:單繼承

class AA
{
public:
	int _aa;
};
class BB :public AA
{
public:
	int _bb;
};

這是一個典型的繼承雖然他什麼也沒有,這裏BB繼承了AA

多繼承:

class AA
{
public:
	int _aa;
};
class BB 
{
public:
	int _bb;
};
class CC : public AA, public BB 。。。
{
public:
	int _cc;
};

這裏的CC同時繼承了AA和BB等,不過正是因爲有了多繼承所以同時帶來了一個問題,就是在繼承中有時會出現一種特殊的情況就是菱形繼承

class AA
{
public:
	int _aa;
};
class BB : public AA
{
public:
	int _bb;
};
class CC : public AA
{
public:
	int _cc;
};
class DD : public BB, public CC
{
public:
	int _dd;
};

這裏BB繼承了AA,CC也繼承了AA,但是DD同時繼承了BB和CC,更直觀一點的就是


這樣子的話很明顯在DD中就會有兩份AA中的函數和變量,這樣就會帶來二義性和數據冗餘的問題,那麼就得想辦法解決這些問題了

首先一種就是我們可以聲明我們具體是給哪一個父類中的變量賦值,例如

int main()
{
DD d;
d.BB::_aa = 10;
d.CC::_aa = 20;
return 0;
}

這樣就可以賦值成功,不過這樣只是解決了二義性的問題,數據冗餘的問題並沒有解決,所以又引入了一個新的解決辦法,叫做虛繼承,其關鍵字爲virtual;用法如下:

class AA
{
public:
	int _aa;
};
class BB :virtual public AA
{
public:
	int _bb;
};
class CC :virtual public AA
{
public:
	int _cc;
};
class DD : public BB, public CC
{
public:
	int _dd;
};

這個時候再對對象d中的_aa賦值

int main()
{
	DD d;
	d._aa = 10;
	d._aa = 20;
	return 0;
}

通過調試我們發現


d中的_aa發生變化是不管是BB_aa還是CC中的_aa都發生了改變,不過再往深的話,我們從監視窗口中並看不出來什麼了,我們不清楚他到底是怎麼實現的,所以我們只能用另一種方法,即內存來研究它是怎麼實現的,來解決二義性和數據冗餘的。

首先是不加virtual的,我們看內存可以得到其對象模型爲

然後是虛繼承的情況


根據其中地址得到其位置的下方存了一個數據,並且這個數據根據觀察可以看出來其數據是一個偏移量,並且是當前指針位置到存AA的位置的偏移量;

再來看其切片賦值的時候


發現在給其父類b賦值的時候是連這其指針和偏移量都一起切片賦值過去的

由此我們可以得到幾個結論:

1.在虛繼承中是把公共的數據重新在內存的最後開闢空間存進去,在其原來的位置存放一個指針,指針所指的位置是關於其到公共數據的偏移量。

2.虛繼承是有代價的,並且在其切片賦值的時候,不只是把其數據賦值回去,而是和着其虛繼承之後的指針,偏移量等等一起賦值的

3.虛繼承在查找數據的時候先要拿指針找偏移量然後再找其數據,犧牲了性能方面,是典型的時間換空間的做法


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