【探索】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

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