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

    C++的虛繼承主要解決了數據冗餘與二義性的問題,起實現方法是什麼呢,我們先看一段代碼。

#include<iostream>
using namespace std;
class A
{
public:
	int _num;
};
class B1 : public A
{

};
class B2 : public A
{

};
class C : public B1, public B2
{

};
int main()
{
	C c;
	cout << sizeof(c) << endl;
	c.B1::_num = 1;
	c.B2::_num = 2;
	cout << "c.B1::_num:" << c.B1::_num << endl;
	cout << "c.B2::_num:" << c.B2::_num << endl;
	cout << "c._num:" << c._num << endl;
	return 0;
}

    這是一個菱形繼承,直接訪問兩個域中的_num並賦不同值時,兩個域中的_num不會是同一個數值,證明了c中含有兩個_num成員變量。當我們訪問C域的_num,系統無法識別到底是訪問B1所繼承下來的還是B2所被繼承下來的,這裏編譯器會報錯,這裏c的大小爲8個字節,調試點開監視窗口我們可以看到:

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/7D/3A/wKioL1bi3c3h3lZ1AAAWWUq4Ptk376.png" title="6F$D@7`89ITR%CY%YPI87NE.png " alt="wKioL1bi3c3h3lZ1AAAWWUq4Ptk376.png" />

一個C在不同域裏繼承了兩份A類的成員變量,這樣就造成了數據冗餘及二義性。

    如何解決這個問題呢,C++中引入了關鍵字“vritual”在一代繼承時加入關鍵字,修改後我們的代碼爲:

#include<iostream>
using namespace std;
class A
{
public:
	int _num;
};
class B1 : virtual public A
{

};
class B2 : virtual public A
{

};
class C : public B1, public B2
{

};
int main()
{
	C c;
	cout << sizeof(c) << endl;
	c.B1::_num = 1;
	c.B2::_num = 2;
	cout << "c.B1::_num:" << c.B1::_num << endl;
	cout << "c.B2::_num:" << c.B2::_num << endl;
	cout << "c._num:" << c._num << endl;
	return 0;
}

    這時我們發現通過c我們不但可以訪問到自己域的成員變量,還可以訪問到所繼承類的成員變量,並且,當給不同域的同名成員變量賦值之後,它們的外在表現都是同一個值,這樣節解決了二義性與數據冗雜,爲什麼說是外在表現呢,當我們打開調試窗口與內存時我們會看到:

調試窗口:

650) this.width=650;" src="http://s5.51cto.com/wyfs02/M01/7D/3A/wKioL1bi4d-AeIpgAAAZelOlvMM218.png" title="L}_F4XBUJQ82XLD1GQ[XBFW.png" alt="wKioL1bi4d-AeIpgAAAZelOlvMM218.png" />

調試窗口中,c不但包含兩個父類的成員變量,還包含兩個父類共同的父類的成員變量,這時c的大小爲12。更驚奇的是,無論我們通過那個域名對其成員變量進行賦值,其他域的成員變量的值也會隨之改變,這時爲什麼呢。這裏我們打開內存監視窗口:

650) this.width=650;" src="http://s4.51cto.com/wyfs02/M00/7D/3A/wKioL1bi5DKSS83JAACtWgubVrM129.png" title="&c.png" alt="wKioL1bi5DKSS83JAACtWgubVrM129.png" />

這裏我們可以看到,c中存的並不是真正的三個類中的成員變量,而是兩個指針,與一個成員變量,拿着兩個指針究竟指向的是什麼呢,我們再打開更多的內存窗口進行觀察:

第一個指針:

650) this.width=650;" src="http://s2.51cto.com/wyfs02/M02/7D/3A/wKioL1bi5Sfy0Dy3AACVeme6o88788.png" title="ptr1.png" alt="wKioL1bi5Sfy0Dy3AACVeme6o88788.png" />

第二個指針:

650) this.width=650;" src="http://s4.51cto.com/wyfs02/M02/7D/3C/wKiom1bi5MXjDN9jAACZCMQ75lc791.png" title="ptr2.png" alt="wKiom1bi5MXjDN9jAACZCMQ75lc791.png" />

    我們可以發現,這兩個指針都爲空,但是,在這兩個指針底下,卻有兩個數字,這兩個數字又恰好與存放這兩個地址內容所在地址到存放c成員變量所在地址的偏移相同。由此可以看出VS下實現virtual關鍵字解決菱形繼承的二義性與數據冗餘的方法是,通過指針的偏移,使c中所存在的三塊空間,在直接或間接的條件下,指向同一塊空間。

    未完待續

本文出自 “pawnsir的IT之路” 博客,請務必保留此出處http://10743407.blog.51cto.com/10733407/1750123

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