初探虚继承

文章通过示例解释了C++中虚继承的作用,即解决菱形继承带来的成员函数调用二义性问题。同时,讨论了虚继承导致的内存增加,因为每个类会包含一个vbptr来管理虚基类指针。此外,还展示了虚继承如何影响类的内存布局,以及vbtable在其中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么会有虚继承

虚继承通常是用来解决菱形继承的,菱形继承会出现二义性。下面举一个简单的例子:

#include <iostream>
#include <cstdio>

class A
{
public:
	A(){}
public:
	int m_a;
};

class B : public A
{
public:
	B(){}
};

class C : public A
{
public:
	C(){}
};

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

int main()
{
	D d;
	//d.m_a = 1;  报错,二义性
	d.C::m_a = 1;
	d.B::m_a = 2;
	std::cout << sizeof(A) << std::endl;
	std::cout << sizeof(B) << std::endl;
	std::cout << sizeof(C) << std::endl;
	std::cout << sizeof(D) << std::endl;
	return 0;
}
输出:
4
4
4
8

看注释的那句话,存在二义性,编译器不知道调用哪一个m_a;
D占用8个字节,所以里面存在两个m_a
解决方法就是虚继承,将代码简单修改

#include <iostream>
#include <cstdio>

class A
{
public:
	A(){}
public:
	int m_a;
};

class B : virtual public A
{
public:
	B(){}
};

class C : virtual public A
{
public:
	C(){}
};

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

int main()
{
	D d;
	d.m_a = 1; 
	std::cout << sizeof(A) << std::endl;
	std::cout << sizeof(B) << std::endl;
	std::cout << sizeof(C) << std::endl;
	std::cout << sizeof(D) << std::endl;
	return 0;
}
输出:
4
8
8
12

可以看见,菱形继承解决了二义性,但是sizeof的空间增大了,这时因为多了vbptr

虚继承vbptr

跟虚函数一样,只有虚函数就一定会用vptr,占用四个字节,那么虚继承也一样,只要有虚继承就一定会有vbptr也是占用4个字节,上面的代码b和c各自都有一个vbptr所以会多4个字节,d因为继承了b和c所以多了两个vbptr

虚继承的内存布局

将代码简单改造

#include <iostream>
#include <cstdio>

class A1
{
public:
	A1()
	{
		printf("A的this=%p\n", this);
	}
public:
	int m_a;
};

class B1 : virtual public A1
{
public:
	B1()
	{
		printf("B1的this=%p\n", this);
	}
public:
	int m_B1;
};

class C1 : virtual public A1
{
public:
	C1()
	{
		printf("C的this=%p\n", this);
	}
public:
	int m_c;
};

class D1 : public B1, public C1
{
public:
	D1()
	{
		printf("D的this=%p\n", this);
	}
public:
	int m_d;
};

int main()
{
	D1 d;
	d.m_a = 1; 
	return 0;
}
输出:
A的this=001CFDE0
B的this=001CFDCC
C的this=001CFDD4
D的this=001CFDCC

看到B和C占用一个this,A和B都是单独的,根据顺序B->C->A

借助VS工具看一下vbtable

A类

cl /d1 reportSingleClassLayoutA1 初探虚继承.cpp
在这里插入图片描述
A类就一个m_a变量

B类

cl /d1 reportSingleClassLayoutB1 初探虚继承.cpp
在这里插入图片描述
B类有一个vbptr和m_b1变量和父类m_a的变量

C类

cl /d1 reportSingleClassLayoutC1 初探虚继承.cpp
在这里插入图片描述
C类有一个vbptr和m_c变量和父类的m_a变量

D类

cl /d1 reportSingleClassLayoutD1 初探虚继承.cpp
在这里插入图片描述
B类有B1和C1的vbptr和变量,还有自己的m_a变量,和爷爷类A1的变量m_a,可以发现一个细节,在虚继承中虚继承的类永远都是放在最后的!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值