類對象所占用的內存空間


  一個類的實例化對象所占空間的大小? 注意不要說類的大小,是類的對象的大小。 首先,類的大小是什么?確切的說,類只是一個類型的定義,它是沒有大小可言的,用sizeof運算符對一個類型名操作,得到的是具有該類型實體的大小

 1 #include <iostream>
 2 
 3 using namespace std;  4 
 5 class A  6 {  7 };  8 
 9 int main() 10 { 11  A obj; 12     int nLen = sizeof(obj); 13     cout << nLen << endl; //sizeof(一個空類)為什么等於1?
14 
15     return 0; 16 }

可以看到一個空類對象的大小1.

一個空類對象的大小是1,為什么不是0?

  初學者肯定會很煩惱?類A明明是空類,它的大小應該為0,為什么編譯器輸出的結果為1呢?這就是實例化的原因(空類同樣被實例化),每個實例在內存中都有一個獨一無二的地址,為了達到這個目的,編譯器往往會給一個空類隱含的加一個字節,這樣空類在實例化后在內存中得到了獨一無二的地址,所以obj的大小是1.

  

打斷點調試的時候,選中obj,然后按快捷鍵shift+F9

可以看到obj的地址是0x0019f77b;然后點擊vs菜單欄上的窗口----內存-----內存(1)

然后把obj的內存地址粘貼過來:

 1 #include <iostream>
 2 
 3 using namespace std;  4 
 5 class A  6 {  7 public:  8     void func1() { };  9     void func2() { }; 10     void func3() { }; 11 }; 12 
13 int main() 14 { 15  A obj; 16     int nLen = sizeof(obj); 17     cout << nLen << endl; //sizeof(一個空類)為什么等於1?
18 
19     return 0; 20 }

此時給類A添加了三個成員函數,此時的類A對象的大小是多少呢?

 

我們看到此時類A對象obj的大小還是1,說明類的成員函數不占用類對象的內存空間

 

 1 #include <iostream>
 2 
 3 using namespace std;  4 
 5 class A  6 {  7 public:  8     void func1() { };  9     void func2() { }; 10     void func3() { }; 11     char ab; 12 }; 13 
14 int main() 15 { 16  A obj; 17     int nLen = sizeof(obj); 18     cout << nLen << endl; // 19 
20     obj.ab = 'c'; 21     return 0; 22 }

我們添加了類A的成員變量ab之后,類A對象的大小是多大呢?

我們看到類A對象obj的大小是1.shift+F9我們獲取到obj的內存地址

當斷點走過obj.ab = 'c'這條賦值語句之后

可以看到原來0bj的內存地址上存儲了63這個十六進制,而十六進制63對應的ASCII碼剛好是字符c,所以說是一個字節大小。同時也說明了成員變量占用類對象的內存空間

 1 #include <iostream>
 2 
 3 using namespace std;  4 
 5 class A  6 {  7 public:  8     void func1() { };  9     void func2() { }; 10     void func3() { }; 11     //char ab;
12     int nab; 13 }; 14 
15 int main() 16 { 17  A obj; 18     int nLen = sizeof(obj); 19     cout << nLen << endl; //
20 
21     //obj.ab = 'c';
22     obj.nab = 12; 23     return 0; 24 }

輸出結果為:

打斷點看到obj的內存地址是0x00cff9b4。而我們可以看到類A的成員變量是占用了4個字節來存儲數據的。

 我們再來看一個例子:

 1 #include <iostream>
 2 
 3 using namespace std;  4 
 5 class A{};  6 class B{};  7 class C : public A  8 {  9     virtual void func() = 0; 10 }; 11 
12 class D : public B, public C 13 { 14 
15 }; 16 
17 int main() 18 { 19     cout << sizeof(A) << endl; 20     cout << sizeof(B) << endl; 21 
22     cout << sizeof(C) << endl; 23     cout << sizeof(D) << endl; 24 
25     return 0; 26 }

輸出結果為:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class A{};
 6 class B1{};
 7 class B 
 8 {
 9     char c;
10 };
11 class C : public A 
12 {
13     virtual void func() = 0;
14 };
15 
16 class D : public B, public C {};
17 
18 class E :public B1, public C {};
19 int main()
20 {
21     cout << sizeof(A) << endl;
22     cout << sizeof(B) << endl;
23 
24     cout << sizeof(C) << endl;
25     cout << sizeof(D) << endl;
26     cout << sizeof(E) << endl;
27 
28     return 0;
29 }

輸出結果:

類A,B的大小為1上面我們已經講過原因,而類C是由類A派生出來的,它里面有一個純虛函數,由於有虛函數的原因,有一個指向虛函數的指針(vptr),在32位的系統分配給指針的大小為4個字節,所以最后得到類C的大小為4個字節(類里只要有一個虛函數,或者說至少有一個虛函數,這個類就會產生一個指向虛函數的指針,有兩個虛函數就會產生兩個指向虛函數的指針,類本身,指向虛函數的指針(一個或者一堆)要有地方存放,這些指針就存放在一個表格里,這個表格我們稱為“虛函數表”,這個虛函數表是保存在可執行文件中的,在程序執行的時候載入到內存中來。不管有幾個虛函數,在32位的系統sizeof()都是多了4個字節)

類D的大小更讓初學者疑惑,類D是由類B,C派生而來的,它的大小應該為二者之和5,為什么是8呢?這是因為為了提高實例在內存中的存取效率,類的大小往往被調整到系統的整數倍,並采取就近的法則,離哪個最近的倍數,就是該類的大小,所以類D的大小為8個字節。

下面我們再看一個例子:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class A
 6 {
 7 private:
 8     int data;
 9 };
10 
11 class B
12 {
13 private:
14     int data;
15     static int xs;
16 };
17 int B::xs = 10;
18 int main()
19 {
20     cout << sizeof(A) << endl;
21     cout << sizeof(B) << endl;
22 
23     return 0;
24 }

輸出結果為:

為什么類B比類A多了一個數據成員,大小卻和類A的大小相同呢?因為類B的靜態數據成員被編譯器放在程序的一個global data members中,它是類的一個數據成員,但是它不影響類的大小,不管這個類實際產生了多少實例,還是派生了多少新的類,靜態成員在類中只有一個實體存在,而類的非靜態數據成員只有被實例化的時候,他們才存在,但是類的靜態數據成員一旦被聲明,無論類是否被實例化,它都已經存在,可以這么說,類的靜態數據成員是一種特殊的全局變量。

下面我們看一個有構造函數,和析構函數的類的大小,它又是多大呢?

 1 #include <iostream>
 2 
 3 using namespace std;  4 
 5 class A  6 {  7 public:  8     A(int a) { x = a; }  9     void func() 10  { 11         cout << x << endl; 12  } 13 
14     ~A() { } 15 private: 16     int x; 17     int g; 18 }; 19 
20 class B 21 { 22 public: 23 private: 24     int a; 25     int b; 26     static int xs; 27 }; 28 
29 int B::xs = 20; 30 
31 int main() 32 { 33     A a(10); 34     //a.func();
35 
36  B b; 37     cout << sizeof(a) << endl; 38     cout << sizeof(b) << endl; 39     return 0; 40 }

它們的結果均相同,可以看出類的大小與它當中的構造函數,析構函數,以及其他的成員函數無關,只與它當中的成員數據有關.

 

從以上幾個例子我們可以總結出來類的大小

1.為類的非靜態成員數據的類型大小之和.
2.由編譯器額外加入的成員變量的大小,用來支持語言的某些特性(如:指向虛函數的指針). 
3.為了優化存取效率,進行的邊緣調整(字節對齊). 
4 與類中的構造函數,析構函數以及其他的成員函數無關.

另外:一個類對象至少占用1個字節的內存空間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM