【探索】VS下實現虛繼承的方法-2

    上篇講到VS下實現虛繼承中成員變量的二義性與數據冗餘的解決方案是怎樣的,今天我們來看看虛繼承的成員函數會如何。

    首先,虛繼承會不會重寫成員函數?我們看一看如下代碼:

#include<iostream>
using namespace std;
class A
{
public:
	void fun()
	{
		cout << "this is fun of A"<<endl;
	}
};
class B1 : public A
{
public:
	void fun()
	{
		cout << "this is fun of B1" << endl;
	}
};
class B2 : public A
{
public:
	void fun()
	{
		cout << "this is fun of B2" << endl;
	}
};
class C : public B1, public B2
{
public:
	void fun()
	{
		cout << "this is fun of C" << endl;
	}
};
int main()
{
	C c;
	c.fun();
	c.B1::fun();
	c.B2::fun();
	c.A::fun();//編譯不通過,對象不存在
}

這裏,主函數中哪條指令編譯不過去呢,明顯是最後一條,因爲調用對象不明確,c繼承了b1,b2,b1,b2中都含有A,c中不直接含有對象a,所以編譯不同過的原因是,系統無法識別我們調用的是b2還是b1中的a,這在某種程度上而言,也是二義性的表現形式,在c中,我們並不需要知道A,B1,B2,的fun(),秩序要知道C中的fun(),這裏我們用虛函數重寫,使得fun()重寫,這樣我們便可以使得C從各個域中的fun()的表現形式變爲一樣嗎?我們來看看虛函數重寫的結果:

wKiom1bkO1WRn7X7AABAcDgBq6s337.png

    答案是不可以的,虛函數重寫,僅僅是將成員函數覆蓋掉,並沒有使派生類中調用基類中的成員函數“銷燬”。派生類仍可以通過域訪問到基類中的成員函數。那如果我們使用虛繼承呢?

答案還是不可以的:

wKiom1bkPeShvt55AABBTImrJsA143.png

打開監視窗口,我們發現,C中包含3個虛表指針,每一個虛表指針都是存的是c::fun()的地址,但是還是可以通過域訪問到不同的fun(),如果我們把A中添加一成員變量,通過內存觀察,(這與我們上一篇講到的一樣,爲了解決數據冗餘,虛繼承使得菱形繼承中的超類得成員變量僅有一份存儲在派生類中,兩個基類會以指針偏移的方式訪問同一個數據,在VS2013下,並沒有存儲真正的基類的成員變量,這是一種優化),在以前vs版本,可能派生類還能保存基類中成員變量的數據。而成員函數,並不是存儲在對象中的內容,故通過域訪問,還是可以修改的。

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