C++对象模型(二)

本文探讨了C++中未继承虚函数的基类和派生类大小,以及在基类包含虚函数且派生类重写或不重写时的内存布局。着重分析了虚函数表对对象大小的影响以及多态实现原理。
摘要由CSDN通过智能技术生成

        上一篇文章里点这里说到了一个类的大小,是单一未继承的类,并没有涉及派生类的大小,而如果是一个派生类呢,它的大小会受基类大小影响吗?

#include <stdio.h>
#include <stdlib.h>

#pragma pack(4)
class CBase
{
public:
	CBase():bBaseValue(300)
	{}
	~CBase()
	{}
private:
	int bBaseValue;
};

class CTest: public CBase
{
public:
	CTest(): mValue(200)
	{
		
	}
	virtual ~CTest()
	{
		
	}

	virtual void print()
	{
		printf("mValue = %d\n", mValue);
	}
private:
	int mValue;
};
#pragma pack()

int main()
{
	CTest test;
	printf("sizeof CTest is %llu\n", sizeof(test));
	return 0;
}

基类 CBase 只有一个成员数据 bBaseValue,应该是 4 字节。那它的派生类的大小是多少呢?

这个派生类的大小,包含了基类的大小 4,和自身的大小 12 ,一共 16 个字节。这里涉及到了添加继承后,类的对象模型,我们还是用 GDB 看一看:

 

0x0000012c (十进制 300) 就是基类的成员数据,从实际内存中我们可以看到派生类里,对象起始位置依然保存的是指向虚表的指针,然后是基类数据,最后才是派生类自身的数据,更形象的图形表示类似这样:

这是基类没有虚函数的情况下,而基类有虚函数的情况,那派生类的内存情况是怎样的呢?

可以看到基类的虚函数放在了虚函数表的第一个位置,其后才是派生类的虚函数。而这种情况是派生类没有重写基类的虚函数,如果派生类重写基类的虚函数呢?

#include <stdio.h>
#include <stdlib.h>

#pragma pack(4)
class CBase
{
public:
	CBase():bBaseValue(300)
	{}
	~CBase()
	{}
	virtual void print()
	{
		printf("CBase Value = %d\n", bBaseValue);
	}
private:
	int bBaseValue;
};

class CTest: public CBase
{
public:
	CTest(): mValue(200)
	{
		
	}
	virtual ~CTest()
	{
		
	}

	virtual void print()
	{
		printf("in CTest mValue = %d\n", mValue);
	}
private:
	int mValue;
};
#pragma pack()

int main()
{
	CTest test;
	printf("sizeof CTest is %llu\n", sizeof(test));
	return 0;
}

 派生类重写了基类的 print() 函数,那派生类对象里的内存情况变得如何了呢?

虚函数表里只有 3 个函数指针了,原来基类虚函数的指针被派生类的重写函数覆盖了,这个是不是就是 C++ 的多态实现?

以下情况是基类有 2 个虚函数,派生类重写了其中一个虚函数:

#include <stdio.h>
#include <stdlib.h>

#pragma pack(4)
class CBase
{
public:
	CBase():bBaseValue(300)
	{}
	~CBase()
	{}
	virtual void basePrint()
	{
		printf("CBase Value = %d\n", bBaseValue);
	}
	virtual void print()
	{
		printf("override Value = %d\n", bBaseValue);
	}
private:
	int bBaseValue;
};

class CTest: public CBase
{
public:
	CTest(): mValue(200)
	{
		
	}
	virtual ~CTest()
	{
		
	}

	virtual void print()
	{
		printf("in CTest mValue = %d\n", mValue);
	}
private:
	int mValue;
};
#pragma pack()

int main()
{
	CTest test;
	printf("sizeof CTest is %llu\n", sizeof(test));
	return 0;
}

 可以看到,虚函数表里第一个永远是基类的虚函数指针,如果被派生类重写了,则用派生类的虚函数指针替换掉基类的虚函数指针,不被重写则依然是基类的虚函数指针。还有更复杂的情况是多重继承、虚继承,还得学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值