C++(对象模型):02---C++对象内存大小模型

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

一、无继承下的对象内存模型

演示案例

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字节)
    • 因此ZooAnimal类对象的大小为:string(28字节)+int(4字节)+虚函数表指针(4字节)=36字节

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

二、有继承关系的对象内存模型

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

演示案例

  • 如果我们有一个类继承于上面的那个ZooAnimal
class Bear :public ZooAnimal {
	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为虚函数表指针

三、虚继承下的内存模型

演示案例

#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;
};

发布了1300 篇原创文章 · 获赞 827 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/103796664