【C++】虚函数与虚拟继承的内存布局规则

在很多面试或口试题中经常涉及到类,而这其中又不得不说类的继承,虚继承,虚函数等问题,所以涉及到了类的内存布局,其中关于虚拟继承(virtual public)这个话题比较难以懂得,而且不同的编译器环境可能实现的类的内存布局不同,所以本文仅在vs2013编译环境下调试,如果你在像gcc这样的编译器中调试结果会不同(gcc中会把虚基指针和虚函数指针合并)。

首先我们要区分虚函数和虚拟继承:

虚拟继承和虚函数是完全无相关的两个概念。

虚函数实现原理

每个虚函数都会有一个与之对应的虚函数表,该虚函数表的实质是一个指针数组,存放的是每一个对象的虚函数入口地址。对于一个派生类来说,他会继承基类的虚函数表同时增加自己的虚函数入口地址,如果派生类重写了基类的虚函数的话,那么继承过来的虚函数入口地址将被派生类的重写虚函数入口地址替代。那么在程序运行时会发生动态绑定,将基类指针绑定到实例化的对象实现多态。
在这里插入图片描述

虚拟继承实现原理

虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。

对比

1、虚继承对比虚函数的实现原理:他们有相似之处,都利用了虚指针(均占用类的存储空间)和虚表(均不占用类的存储空间)。

2、虚基类依旧存在继承类中,占用存储空间;虚函数不占用存储空间。

3、虚基类表存储的是虚基类相对直接继承类的偏移;而虚函数表存储的是虚函数地址。

测试

准备工作

VS2013使用命令行选项查看对象的内存布局
在这里插入图片描述
在这里插入图片描述
格式:
[filename].cpp /d1 reportSingleClassLayout[className]
测试代码GitHub地址

测试一:单个虚继承,不带虚函数

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

//测试一:单个虚继承,不带虚函数

class A
{
   
public:
	A() : _ia(10){
   }

	/*virtual*/
	void f()
	{
   
		cout << "A::f()" << endl;
	}
private:
	int _ia;
};

class  B
: virtual public A
{
   
public:
	B() : _ib(20){
   }
	
	void fb()
	{
   
		cout << "B::fb()" << endl;
	}
	/*virtual*/
	void f()
	{
   
		cout << "B::f()" << endl;
	}

	/*virtual*/
	void fb2()
	{
   
		cout << "B::fb2()" << endl;
	}

private:
	int _ib;
};

 
int main(void)
{
   
	cout << sizeof(A) << endl;
	cout << sizeof(B) << endl;
	B b;
	system("pause");
	return 0
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值