C++多继承虚函数类内部模型结构剖析

本文通过具体示例对比分析了C++中多继承和虚继承情况下类的内部结构及成员分布特点,展示了虚继承如何避免基类数据成员的重复。

这里主要看看C++在多继承含有虚函数的情况下类的内部成员结构和分布。

类继承体系代码如下,先看看非虚继承的情况:

class Base{
public:
	Base(){}
	virtual ~Base(){}
	virtual void v(){}
	void f(){}
public:
	int data_Base;
};
class Base1 :  public Base{
public:
	Base1(){}
	virtual ~Base1(){}
	virtual void v1(){}
	void f1(){}
public:
	int data_Base1;
};

class Base2 :  public Base{
public:
	Base2(){}
	virtual ~Base2(){}
	virtual void v2(){}
	void f2(){}
public:
	int data_Base2;
};

class Derived : public Base1, public Base2 {
public:
	Derived(){}
	virtual ~Derived(){}
	virtual void v(){}
	virtual void v1(){}
	virtual void v2(){}
	virtual void v3(){}
	void f3(){}
public:
	int data_Derived;
};

使用VS2010提供的Command Prompt工具里的"cld1"命令查看类的结构如下:


由此可以看到,Derived类在内存里由低到高地址存储的分别是:

vfptr(虚函数表指针,包含Derived类新增的虚函数以及重写的或未重写的Base1基类的虚函数);

data_Base(Base基类的成员变量);

data_Base1(Base1基类的成员变量);

vfptr(虚函数表指针,包含Derived类重写的或未重写的Base2基类的虚函数);

data_Base(Base基类的成员变量);

data_Base2(Base2基类的成员变量);

data_Derived(Derived基类的成员变量);

总共28个字节,以下是测试代码:

int main(void)
{
	Base1 base1;
	Derived derived;
	int *p1 = (int*)(&base1);
	int *p2 = (int*)(&derived);
	derived.data_Base1 = 3;
	derived.data_Base2 = 4;
	derived.Base1::data_Base = 1;
	derived.Base2::data_Base = 2;
	derived.data_Derived = 5;
	for (int i = 0; i < 10; i++)
	{
		cout << hex <<p2<<":"<<hex<<*p2++ << endl;
	}
	cout << "derived size:" <<dec<< sizeof(derived) << endl;
	int a = 0;
	cin >> a;
	return 0;
}

代码打印从Derived实例内存首地址开始的十个整形数据,结果如下:


与上面分析的一致,可以看出Derived包含了基类Base的两份数据,因此需要使用虚继承去掉公共基类的数据重复,加上虚继承后的类代码如下:

class Base{
public:
	Base(){}
	virtual ~Base(){}
	virtual void v(){}
	void f(){}
protected:
	float data_Base;
};
class Base1 : virtual  public Base{
public:
	Base1(){}
	virtual ~Base1(){}
	virtual void v1(){}
	void f1(){}
protected:
	float data_Base1;
};

class Base2 : virtual  public Base{
public:
	Base2(){}
	virtual ~Base2(){}
	virtual void v2(){}
	void f2(){}
protected:
	float data_Base2;
};

class Derived : public Base1, public Base2 {
public:
	Derived(){}
	virtual ~Derived(){}
	virtual void v(){}
	virtual void v1(){}
	virtual void v2(){}
	virtual void v3(){}
	void f3(){}
protected:
	float data_Derived;
};

类结构分析结果如下:


由此可以看到,加上虚继承后Derived类在内存里由低到高地址存储的分别是:

vfptr(虚函数表指针,包含Derived类新增的虚函数以及重写的或为重写的Base1基类的虚函数);

vbptr(Base1基类指向公共基类成分部分的指针)

data_Base1(Base1基类的成员变量);

vfptr(虚函数表指针,包含Derived类重写的或未重写的Base2基类的虚函数);

vbptr(Base2基类指向公共基类成分部分的指针)

data_Base2(Base2基类的成员变量);

data_Derived(Derived基类的成员变量);

vtordip(C++虚继承机制历史遗留的成员,始终为0);

vbptr(虚函数表指针,包含Derived类重写的或未重写的Base基类的虚函数);

data_Base(Base公用基类的成员变量)

总共40个字节,以下是测试代码:

int main(void)
{
	Base1 base1;
	Derived derived;
	int *p1 = (int*)(&base1);
	int *p2 = (int*)(&derived);
	derived.data_Base1 = 3;
	derived.data_Base2 = 4;
	derived.data_Base = 1;
	derived.data_Derived = 5;
	for (int i = 0; i < 10; i++)
	{
		cout << hex <<p2<<":"<<hex<<*p2++ << endl;
	}
	cout << "derived size:" <<dec<< sizeof(derived) << endl;
	int a = 0;
	cin >> a;
	return 0;
}


OK,与上面分析的一致。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值