GCC编译环境C++类对象存储结构

严谨声明以下结论均为GCC编译和UNIX 64位系统环境下得出的结论,非GCC和UNIX环境结论部分结论可能有所不同

1.C++类成员变量分为两部分:类自身声明的成员变量,来自于基类的成员变量

2.成员变量在内存中的顺序和声明顺序保持一致,从低地址向高地址扩展

3.直接继承的情况下, 基类成员变量的地址,在子类成员变量的地址之前;

4.虚继承的情况下,基类成员变量的地址,在子类成员变量的地址之后;

5.虚函数表指针,处于所有对象指针之前

完整的验证代码:

#include
using namespace std;

class base
{
 public:
 int base_a;
 virtual void method(){};
};

class A: public base
{
 public: 
 int a;
 int b;
 int c;
 virtual void method(){};
};

int main()
{
 A obj;

 cout<<"address obj:"<<&obj<

有虚函数的情况下输出(64位的环境,一个指针占8个字节):

address obj:0x7ffee9fe99b0 #(对象起始地址)
address base_a:0x7ffee9fe99b8 #(基类的一个成员变量起始地址)
address a:0x7ffee9fe99bc #(子类的第一个成员变量起始地址)
address b:0x7ffee9fe99c0 #(子类的第二个成员变量起始地址)
address c:0x7ffee9fe99c4 #(子类的第三个成员变量起始地址)

可以看出(对象起始地址)和(基类的一个成员变量起始地址)中间差了一个指针的空间,把基类和子类的虚函数注释掉之后看看输出:

address obj:0x7ffeec0d39c0 #(对象起始地址)
address base_a:0x7ffeec0d39c0 #(基类的一个成员变量起始地址)
address a:0x7ffeec0d39c4
address b:0x7ffeec0d39c8
address c:0x7ffeec0d39cc

所以可以猜想虚函数指针被编译器安插在了对象的头部,指针占用固定长度字节。

虚继承的情况下程序输出:

 

address obj:0x7ffee15359b0 #(对象起始地址)
address base_a:0x7ffee15359c4 #(基类成员变量在最后)
address a:0x7ffee15359b8 #(子类的第一个成员变量起始地址)
address b:0x7ffee15359bc #(子类的第二个成员变量起始地址)
address c:0x7ffee15359c0 #(子类的第三个成员变量起始地址)

 

你可能感兴趣的:(C++)