菱形继承问题以及虚拟继承探究

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liu_zhen_kai/article/details/82806162

在前边的博客中我提到过菱形继承的问题,也给出了几种解决菱形继承的方法

https://blog.csdn.net/liu_zhen_kai/article/details/81590467

但是给的方法没有说明原因,这篇博客将会从内存存储模型角度,以及虚继承为什么可以使解决菱形继承的问题进行阐述与证明。

 所谓菱形继承就是指类B,类C同时继承A,且D同时继承B,C,在A具有成员函数的情况下,在D类实例化出来的对象中对A的成员函数进行直接调用会发生二义性的问题,也就是编译器不知道是寻找B继承的成员函数还是A继承的成员函数。

但是在B,C继承A的时候,加上虚继承则不会发生错误

但是为什么虚继承会使得这种问题得以解决呢?

原因是虚继承其实改变了传统的类继承的空间结构模型,可以在内存显示窗口看到

为了使得内存易于找到,在A中放入几个值,则有以下代码:

#include <iostream>
using namespace std;

class A
{
public:
	A()
		:a(1)
	{}
	void Print(void) {
		cout << "hello" << endl;
	}

	int a;

};

class B:virtual public A{
public:
	B() 
		:b(2)
	{}
	int b;
};

class C:virtual public A{
public:
	C()
		:c(3)
	{}
	int c;
};

class D:public B, public C{
public:
	D() 
		:d(4)
	{}
	int d;
};

int main()
{
	D d;
	d.Print();
	return 0;
}

运行起来内存分布结构为:

显而易见的结果是:

最底部为A的成员,有A的独立数据,在A之上存放D的独有数据,D之上存放着C的独有数据的同时有一个类似地址的十六进制值,同时B也有一个类似地址的值。

若是地址,我们可以在内存中寻找该地址所对应的是什么内容,于是我们有以下访问地址操作:

查询地址0x00 2d 9b 50 与 0x00 2d 9b 5c所对应的值

注:为何我在查询地址的过程中将地址俩俩倒过来写?因为由于我所用的计算机是小端机器,低地址存高位,所以在查内存时需要反过来写。

查询结果为:14和0c,那么这两个数字指向的地址值到底是代表什么意思呢?

其实给它们分别为记录对A的偏移量。

在虚继承的过程中,派生类独有数据之前都会有一个指针,这个指针指向一张名为“虚基表”的数据结构,该数据结构记录了许多信息,其中就会包括它们对于父类的偏移量,在我们D进行A成员函数操作的时候,找到地址,会寻找到A的成员函数地址,在进行Call调用,这样就彻底的解决了菱形继承的问题。

猜你喜欢

转载自blog.csdn.net/liu_zhen_kai/article/details/82806162
今日推荐