c++对象模型02——C++对象内存大小模型

C++对象的内存大小由以下几个方面决定:

  • 空类的大小默认为1
  • 类中非静态成员的总和
  • 如果有继承,派生类的对象会加上基类对象的数据成员
  • 如果有virtual,那么就需要加上一个虚函数表指针的大小(在继承方式下,父子类共享一个虚函数表,因此子类的虚函数表指针是继承于父类的,不会新增一个虚函数表指针)
  • 内存对齐补齐规则

1. 无继承下的对象内存模型

案例:

class ZooAnimal {
public:
	ZooAnimal()=default;
	virtual ~ZooAnimal() {}
	virtual void rotate() {}
 
protected:
	int loc;
	std::string name;
};
 
int main()
{
	std::string s;
	std::cout << sizeof(s) << std::endl;
 
	ZooAnimal za;
	ZooAnimal *pza = &za;
 
	std::cout << "sizeof ZooAnimal is " << sizeof(za) << std::endl;
 
	return 0;
}

演示结果:

  • 下面在32位编译器下运行(指针大小为4字节,string的大小为28字节)64位编译器下string为40个字节。
  • 因此ZooAnimal类对象的大小为:string(28字节)+int(4字节)+虚函数表指针(4字节)=36字节

其内存模型如下:

  • 假设pza指针所指的地址为1000,其指向的对象模型如下所示
  • __vptr为虚函数表指针

 

 2. 有继承关系的对象内存模型

派生类的内存空间中会包含基类的内存成员,并且派生类会将自己的新数据成员新增在自己的内存模型中。

演示案例:

  • 如果我们有一个类继承于上面的那个ZooAnimal
class Bear :public ZooAnimal {
public:
	Bear() {}
	~Bear() {}
 
	void rotate() {}
	virtual void dance() {}
 
protected:
	enum Dances {};
 
	Dances dances_known;
	int cell_block;
};
 
int main()
{
 
	std::string s;
	std::cout << sizeof(s) << std::endl;
 
	ZooAnimal za;
	ZooAnimal *pza = &za;
 
	std::cout << "sizeof ZooAnimal is " << sizeof(za) << std::endl;
 
	Bear b;
	Bear *pb = &b;
	Bear &rb = *pb;
 
	std::cout << "sizeof ZooAnimal is " << sizeof(b) << std::endl;
 
	return 0;
}

演示结果:

  • 下面在32位编译器下运行(指针大小为4字节,string的大小为28字节)
  • 因此Bear类对象的大小为:string(28字节)+int(4字节)+虚函数表指针(4字节)+dances_known(4字节)+cell_block(4字节)=44

其内存模型如下:

  • 假设pb指针的所指的地址为1000,其指向的对象模型如下所示
  • __vptr为虚函数表指针

 

3. 虚继承下的内存模型

演示案例

#include<stdio.h>
 
class X{};
 
class Y :virtual public X {};
 
class Z :virtual public X {};
 
class A :public Y, public Z {};
 
int main()
{
	X x;
	printf("sizeof x is %d\n", sizeof(x));
 
	Y y;
	printf("sizeof y is %d\n", sizeof(y));
 
	Z z;
	printf("sizeof z is %d\n", sizeof(z));
 
	A a;
	printf("sizeof a is %d\n", sizeof(a));
 
	return 0;
}
  • x:空类的大小为1
  • y:有虚函数表指针,指针为4字节(32位机器上)
  • z:有虚函数表指针,指针为4字节(32位机器上)
  • a:两个虚函数表指针,一个指向于y,一个指向于z

如果我们把X改为以下形式,则:

  • x:a为int,因此为4
  • y:一个虚函数表指针(4字节)+a的大小(4字节)
  • z:一个虚函数表指针(4字节)+a的大小(4字节)
  • a:两个虚函数表指针(8字节,一个指向于y,一个指向于z)+a的大小(4字节,因为virtual继承只会保存一份基类的实例,所以只有一个a)
class X
{
	int a;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值