当我们需要招一个C++工程师的时候,我一般会简单问一下 C++ 的基本概念。比如:static 的作用,const 的作用等。这些基本概念回答完后,我会问几个关于对象模型的问题来评定级别。
有几次突发奇想的问了一下sizeof 的几个问题。
class A {}; sizeof(A)=?
这个问题只要了解过的人都知道等于1,如果回答0,那你可能就是一个C++入门不久的人,后续也就不会再问更深入的问题了。
由这个问题会引出别的问题,比如成员函数占用多少空间,成员变量会占用多少空间,虚函数引入之后会占用多少空间。虚拟继承,定义类时的优化等等问题。这些问题会在后续的一系列文章里介绍。
先来个入门的,成员函数和成员变量占用空间的问题。
如果在上面这个类中加入一个成员函数,sizeof 的结果还是1,这说明成员函数不会引入额外的空间占用。
如果在上面这个类中加入一个成员变量,sizeof 的结果会随着变量类型不同而不同。
如果在上面这个类中加入多个成员变量,sizeof 的结果可能会因为顺序的不同而不同。
首先来看,为什么没有任何成员变量时,sizeof 的结果是1而不是0.
- 编译器没有在编译的时候提出质疑这中空类不允许存在
- 在调用 new 方法的时候,编译器要做两件事,分配内存和调用构造函数(编译器会根据自己的需要,为这个类生成必要的构造函数,这个会在后续的系列中介绍)
这时候问题来了,需要分配多少内存空间呢?如果是0的话,那么是不是应该分配大小为0 的空间呢?这让编译器太为难了吧。怎么能分配空间为0,然后还能保证对象的唯一性呢?(独一无二的地址) 那还是默认给它1,这样我还能正常的工作下去,多了也浪费。这就是为什么需要给空类默认1的空间了。
为什么成员函数不会占用内存空间呢?(非虚函数)
- 其实成员函数会占用内存空间的。
- 多个对象使用的成员函数是一样的(非虚函数,所以执行的代码是一样的)
- 系统为成员函数分配内存,但是所有对象是共享的。
- 编译器在编译到调用成员函数的地方,会为成员函数自动加上 this 指针,这样相当于每个对象实例调用成员函数时会有不同的参数
系统只需要为这种非虚函数保留一份内存,而不需要为每个对象实例都分配一块儿内存来浪费空间。
因为各类型所需要的空间不一样,所以成员变量的类型会导致占用空间不同。
为什么有多个成员变量时,顺序可能会影响类的大小呢?
想看一个例子
class A1 { char c1; int i; char c2; }; class A2 { char c1; char c2; int i; }; class A3 { int i; char c1; char c2; };
这上边的三个不同的类,其成员变量是一样的,我们看看结果怎样:
sizeof(A1) = 12; sizeof(A2) = sizeof(A3) = 8.
为什么不是6呢?第一个类的大小为什么是12呢?第二个和第三个为什么都是8呢?
- char 的大小为1
- 默认按照4位对齐,不足4位,补0对齐
- int 在32位下是4