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.虚继承在查找数据的时候先要拿指针找偏移量然后再找其数据,牺牲了性能方面,是典型的时间换空间的做法


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