虚拟继承,虚函数的详细内存布局三

文章讲述了在C++中,当类D同时继承自B1和B2,且B1和B2都虚继承自B时,如何通过虚拟继承机制消除访问B函数时的二义性问题。通过介绍虚基指针和虚基表的工作原理,解释了为何虚拟继承可以避免内存中的数据成员冲突。
摘要由CSDN通过智能技术生成

测试四:菱形虚继承

4.1、菱形普通继承(存储二义性)

        

#pragma vtordisp(off)
#include <iostream>
using std::cout;
using std::endl;

class B
{
public:
	B() : _ib(10), _cb('B') {}

	virtual void f()
	{
		cout << "B::f()" << endl;
	}

	virtual void Bf()
	{
		cout << "B::Bf()" << endl;
	}

private:
	int _ib;
	char _cb;
};

class B1 : /*virtual*/ public B
{
public:
	B1() : _ib1(100), _cb1('1') {}

	virtual void f()
	{
		cout << "B1::f()" << endl;
	}

	virtual void f1()
	{
		cout << "B1::f1()" << endl;
	}
	virtual void Bf1()
	{
		cout << "B1::Bf1()" << endl;
	}

private:
	int _ib1;
	char _cb1;
};

class B2 : /*virtual*/ public B
{
public:
	B2() : _ib2(1000), _cb2('2') {}

	virtual void f()
	{
		cout << "B2::f()" << endl;
	}
	virtual void f2()
	{
		cout << "B2::f2()" << endl;
	}

	virtual void Bf2()
	{
		cout << "B2::Bf2()" << endl;
	}
private:
	int _ib2;
	char _cb2;
};

class D : public B1, public B2
{
public:
	D() : _id(10000), _cd('3') {}

	virtual void f()
	{
		cout << "D::f()" << endl;
	}

	virtual void f1()
	{
		cout << "D::f1()" << endl;
	}

	virtual void f2()
	{
		cout << "D::f2()" << endl;
	}

	virtual void Df()
	{
		cout << "D::Df()" << endl;
	}
private:
	int _id;
	char _cd;
};

int main(void)
{
	D d;
	cout << sizeof(d) << endl;

	return 0;
}

内存布局:

D中有从B1中继承来的B的数据成员,也有从B2中继承来的B的数据成员,如果d访问Bf()函数的话就会造成二义性,不知道是要访问B1中从B继承来的Bf还是B2中从B继承来的Bf

所以需要虚拟继承来解决二义性问题

4.2、菱形虚拟继承

class B
{
public:
	B() : _ib(10), _cb('B') {}

	virtual void f()
	{
		cout << "B::f()" << endl;
	}

	virtual void Bf()
	{
		cout << "B::Bf()" << endl;
	}

private:
	int _ib;
	char _cb;
};

class B1 : virtual public B
{
public:
	B1() : _ib1(100), _cb1('1') {}

	virtual void f()
	{
		cout << "B1::f()" << endl;
	}
	virtual void f1()
	{
		cout << "B1::f1()" << endl;
	}
	virtual void Bf1()
	{
		cout << "B1::Bf1()" << endl;
	}
private:
	int _ib1;
	char _cb1;
};

class B2 : virtual public B
{
public:
	B2() : _ib2(1000), _cb2('2') {}

	virtual void f()
	{
		cout << "B2::f()" << endl;
	}
	virtual void f2()
	{
		cout << "B2::f2()" << endl;
	}

	virtual void Bf2()
	{
		cout << "B2::Bf2()" << endl;
	}
private:
	int _ib2;
	char _cb2;
};

class D : public B1, public B2
{
public:
	D() : _id(10000), _cd('3') {}

	virtual void f()
	{
		cout << "D::f()" << endl;
	}

	virtual void f1()
	{
		cout << "D::f1()" << endl;
	}

	virtual void f2()
	{
		cout << "D::f2()" << endl;
	}

	virtual void Df()
	{
		cout << "D::Df()" << endl;
	}

private:
	int _id;
	char _cd;
};

B1和B2都虚拟继承自B,内存布局:

D继承自B1和B2,B1和B2虚拟继承自B,B1和B2都有自己的虚基指针,指向自己的虚基表,虚基表中第二个偏移量是各自的虚基指针距离虚基类B子对象的偏移,虚基类B的内存布局只有一份,不会造成二义性,所以就解决了二义性的问题

看一下linux下的内存布局:这里是gdb查看

也可以使用下面的命令生成内存文件查看:

g++ -fdump-class-hierarchy virtual3.cpp

这个文件就是内存布局文件

linux下的d对象里面没有虚基指针,B的内存布局只有一份,也没有二义性问题

这里和vs上的不一样,毕竟编译器不一样,本文测试的是vs下的,就不深入探索linux环境下的类内存布局了

总结:

        虚拟继承能够解决二义性问题,因为是虚拟继承就有虚基指针,虚基指针指向虚基表,虚基表里第一条内容表示的是该虚基指针距离所在的子对象的首地址的偏移,虚基表的第二条内容表示的是该虚基指针距离虚基类子对象的首地址的偏移,虚基类子对象只有一份,就解决了二义性的问题

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值