GCC編譯環境C++類對象存儲結構

嚴謹聲明以下結論均爲GCC編譯和UNIX 64位系統環境下得出的結論,非GCC和UNIX環境結論部分結論可能有所不同

1.C++類成員變量分爲兩部分:類自身聲明的成員變量,來自於基類的成員變量

2.成員變量在內存中的順序和聲明順序保持一致,從低地址向高地址擴展

3.直接繼承的情況下, 基類成員變量的地址,在子類成員變量的地址之前;

4.虛繼承的情況下,基類成員變量的地址,在子類成員變量的地址之後;

5.虛函數表指針,處於所有對象指針之前

完整的驗證代碼:

#include<iostream>
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<<endl;
 cout<<"address base_a:"<<&obj.base_a<<endl;
 cout<<"address a:"<<&obj.a<<endl;
 cout<<"address b:"<<&obj.b<<endl;
 cout<<"address c:"<<&obj.c<<endl;
return 0;
}

有虛函數的情況下輸出(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 #(子類的第三個成員變量起始地址)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章