进入主题前,先把工具设置好。本文使用编译测试环境:Visual Studio 2013
VS2013查看类内存布局设置方式如下截图:
先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存布局,如果写上/d1 reportSingleClassLayoutXXX(XXX为类名),则只会打出指定类XXX的内存布局。
进入主题:从最基础的class到继承、多重继承、虚拟继承,我们依次展开来看。
1.空类
定义一个空类,如下:
class Base {
};
编译一下,可以看到输出框里面的布局:
发现空类Base的size是1,原因:C++标准规定,编译器为空类插入1字节的char,以使该类对象在内存得以配置一个地址。
2.普通类(只有nonstatic的成员变量)
定义如下:
class Base {
private:
int a;
int b;
};
内存布局:
这里暂不考虑字节对齐的影响,所以成员变量都设为int型。从这里可以看到普通类的布局方式,nonstatic成员变量依据声明的顺序进行排列(类内偏移为0开始)。
当涉及字符对齐时的内存布局图。
定义如下:
class Base {
private:
int a;
char b;
};
内存布局:
从上图红色框图中,看到char b会被4byte对齐,Base object size是8,而不是5。
当在继承体系中,父类和子类都涉及字节对齐时,我们来看下内存布局状况。
定义如下:
class Base {
private:
int a;
char b;
};
class Derived : public Base{
private:
int c;
char d;
};
内存布局:
从上图红色框图中,看到Base suboject char b和Derived char d 都被4byte对齐,Derived object size是16。int c的内存并不是从位置5开始,而是从8开始。在继承中char b依然会如Base对象中被4byte对齐处理。这是因为:继承关系中派生类会保持基类subobject的内存布局完整性。
定义如下:
class Base {
public:
void f();
static void g();
private:
int a;
static int c;
int b;
};
内存布局:
可以看出:static成员变量、static成员函数,普通成员函数,都不会占用对象的空间。static成员属于class,所有object共用一份。
4.普通类(加上虚函数)
定义如下:
class Base {
public:
void f();
virtual void g();
private:
int a;
int b;
};
内存布局:
这个结构图分成上下两部分,上面是内存分布,下面是虚函数表vftable(也称作vtbl)。我们看到class Base size现在是12,除去两个int变量占用8个Byte,虚函数表指针vfptr(也称作vptr&#x