C++类的占用空间

面(笔)试的时候经常碰到求C++类的占用空间的问题,尤其是包含了虚函数的单一继承和多重继承时类的占用空间,这里作一下简单的测试和说明。


一、空类的占用空间

    空类的占用空间为1个字节,《深度探索C++对象模型》是这样说的:“那是被编译器插进去的一个char ,使得这个class的不同实体(object)在内存中配置独一无二的地址”,也就是说空类的这个char是用来标识类的不同对象的。这个很容易验证,需要注意的是,这个char是不会进行字节对齐的。


二、单一继承时类的占用空间


#include <iostream>

using namespace std;

class A
{};

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

class C : public B
{
public:
	virtual ~C(){}
	virtual void func2(){}
};

class D : public C
{
public:
	virtual ~D(){}
	virtual void func1(){}
	virtual void func3(){}
	char c;
};

class E : public D
{
public:
	double x;
	static int y;
};

int main()
{
	cout << "A: " << sizeof(A) << endl;
	cout << "B: " << sizeof(B) << endl;
	cout << "C: " << sizeof(C) << endl;
	cout << "D: " << sizeof(D) << endl;
	cout << "E: " << sizeof(E) << endl;

	return 0;
}

输出结果:

A: 1
B: 1
C: 8
D: 16
E: 24

说明:

(1)由A知,空类的大小是1字节

(2)由B知,类的占用空间与成员函数无关

(3)由C知,存在虚函数时,类的占用空间会变大,这里实际上是插入了一个虚表指针(vptr),这个指针指向类的虚函数列表。指针的大小与机器的位数有关,32位机器上指针大小为4个字节,64位机器上是8个字节。

(4)由D知,类的占用空间与成员变量有关。D的大小是类C的占用空间加上char成员变量的1个字节,这里存在字节对齐,即把1一个字节补齐到8个字节,这里浪费掉了7个字节的空间。

(5)由E知,类的占用空间与虚函数的多少无关,都是只有一个虚表指针的大小;与静态成员变量无关,静态成员变量存在于内存的全局存储区,在编译时,编译器将其剔除类的空间,相当于一个全局变量。E的大小是类D的大小加上double变量的大小,是24字节。

(6)假如类E在double成员变量之前有个char成员变量,再有一个int成员变量,那么类E的大小是多少呢?新增加的两个成员变量会不会继续占用类D空出来的7个字节呢?假如这两个变量在double成员变量之后呢?再假如char变量和int变量换一下位置呢?像这样:

class E1 : public D
{
public:
	char a;
	int m;
	double x;
	static int	y;
};

class E2 : public D
{
public:
	int m;
	char a;
	double x;
	static int	y;
};

class E3 : public D
{
public:
	double x;
	char a;
	int m;
	static int	y;
};

class E4 : public D
{
public:
	double x;
	int m;
	char a;
	static int	y;
};

类E1、E2、E3、E4的大小分别是多少呢?在我的机器上(64位),分别是:

E1: 24
E2: 32
E3: 32
E4: 32

类E1的大小居然等于E的大小,24字节,这样看的话E1的char和int成员变量的确可能占用了类D的剩余的7个字节中的5个。但是,类E2的大小却又是32字节,也就是说类E2的int和char成员变量是没有占用类D的剩余字节的。E1和E2的区别只在于前两个成员变量的声明顺序,E2却多出了8个字节,这是什么原因呢?求解。

E3和E4与预想的一样,都是32字节。


三、多重继承时类的占用空间

class G
{
public:
	void func2(){}
};

class H
{
public:
	virtual ~H(){}
	virtual void func4(){}
	char h;
};

class G1 : public D, G
{
};

class G2 : public D, H
{
public:
	char g2;
};

已经知道,G大小是1字节,H大小是16字节(存在字节对齐),G1、G2是多少呢?

按照我们的理解,G1的大小是D的大小加上G的大小,16+1=17,再字节对齐,应该是24字节;G2的大小应该是16+16+1=33,再字节对齐,应该是40字节。

但是,实际上我的运行结果却是:G1是16字节,G2是32字节。

这个结果,是不是可以说空类在继承时不计算其占用空间?G2的char成员变量是不是占用了D或者H的一个剩余空间呢?


按照《深度探索C++对象模型》中关于对象模型的说明,子类在继承父类时,保持父类的对象模型不变,并在父类对象的后面加上自己的成员变量(但会共用一个vptr),也就是说子类不应该占用父类的模型空间。不知道我的理解是否正确,各位看官,有知道以上问题解答的,烦请告知,多谢!


四、参考资料

1、http://blog.csdn.net/hitblue/article/details/3726754

2、http://www.cnblogs.com/snben/archive/2012/08/16/2641667.html

3、《深度探索C++对象模型》


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值