C++虛基類

虛基類存在的意義

先來看一段代碼

#include<bits/stdc++.h>

using namespace std;

class A
{
public:
	void fun()
	{
		cout << "A";
	}
};
class B : public A
{
};
class C : public A
{
};
class D :public B, public C
{
};
int main(void)
{
	D d;
	d.fun();//這裏會報錯 原因:fun()不明確
}

爲什麼這裏會報錯呢 這是應爲A同時是B和C的基類,D同時繼承了B和C,此時要調用A的fun(),編譯器就會不明白到底是要調用B中的fun()還是C中的fun()。

如果將基類定義爲虛基類,則會使派生類中只保留一份拷貝。

#include<bits/stdc++.h>

using namespace std;

class A
{
public:
	void fun()
	{
		cout << "A";
	}
};
class B :virtual public A
{
};
class C :virtual public A
{
};
class D :public B, public C
{
};
int main(void)
{
	D d;
	d.fun();//輸出 A
}

爲什麼會這樣呢?

在定義了虛基類後,就等於告訴編譯器,這裏的基類A是B和C兩個派生類所共有的,對於調用B還是C都是對一個A而言。而對於第一個例子來說,在調用fun()的時候,相當於把A拷貝給了B和C,而彼此和A是無關聯的。

當然,不用虛基類也不是不行,爲了解決此問題,你可以這樣解決,顯示調用某類的函數

int main(void)
{
	D d;
	d.B::fun();//輸出A
}

單一虛繼承的內存結構

在這裏插入圖片描述
虛 擬繼承的子類的內存結構,和普通繼承完全不同。虛擬繼承的子類,有單獨的虛函數表, 另外也單獨保存一份父類的虛函數表,兩部分之間用一個四個字節的0x00000000來作爲分界。子類的內存中,首先是自己的虛函數表,然後是子類的數據 成員,然後是0x0,之後就是父類的虛函數表,之後是父類的數據成員。
如果子類沒有自己的虛函數,那麼子類就不會有虛函數表,但是子類數據和父類數據之間,還是需要0x0來間隔。
因此,在虛擬繼承中,子類和父類的數據,是完全間隔的,先存放子類自己的虛函數表和數據,中間以0x分界,最後保存父類的虛函數和數據。如果子類重載了父類的虛函數,那麼則將子類內存中父類虛函數表的相應函數替換。

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