【轉】C++類的sizeof大小


轉自https://blog.csdn.net/zhengjihao/article/details/77825269

其中有的描述與實際GCC上執行的結果不符,不過其中的分析思路需要掌握。

以下是GCC的實際執行結果:

  1 #include <iostream>
  2 using namespace std;
  3 
  4 int *pointer;
  5 
  6 class NullCls {};
  7 
  8 class NullVirtual {
  9 public:
 10     virtual void fun() {};
 11     virtual void fun2() {};
 12 };
 13 
 14 class CSI {
 15 public:
 16     char b;
 17     short c;
 18     int a;
 19 };
 20 
 21 class CIS {
 22 public:
 23     char b;
 24     int a;
 25     short c;
 26 };
 27 
 28 class CSV {
 29 public:
 30     char b;
 31     short c;
 32     virtual void fun() {};
 33 };
 34 
 35 class CVS {
 36 public:
 37     char a;
 38     virtual void fun() {};
 39     short b;
 40 };
 41 
 42 class StaticInt {
 43 public:
 44     char b;
 45     virtual void fun() {};
 46     static int c;  // 放在程序的global data members中
 47 };
 48 
 49 class Method {
 50 public:
 51     void fun() {};
 52 };
 53 
 54 class Parent {
 55 public:
 56     int c;
 57 };
 58 
 59 class Son : public Parent {
 60 public:
 61     int b;
 62 };
 63 
 64 class Parent2 {
 65 public:
 66     int a;
 67     char b;
 68 };
 69 
 70 class Son2 : public Parent2 {
 71 public:
 72     char c;
 73 };
 74 
 75 class A
 76 {
 77     virtual void fun() {}
 78 };
 79 
 80 class B
 81 {
 82     virtual void fun2() {}
 83 };
 84 
 85 class C : virtual public  A, virtual public B
 86 {
 87 public:
 88     virtual void fun3() {}
 89 };
 90 
 91 class C2 : public A, public B
 92 {
 93 public:
 94     virtual void fun3() {}
 95 };
 96 
 97 void size(string name, int s) {
 98     cout << name << "=" << s << endl;
 99 }
100 
101 int main(){
102     size("pointer", sizeof(pointer));  // 8
103     size("NullCls", sizeof(NullCls));  // 1
104     size("NullVirtual", sizeof(NullVirtual));  // 8
105     size("CSI", sizeof(CSI));  // 8
106     size("CIS", sizeof(CIS));  // 12
107     size("CSV", sizeof(CSV));  // 16
108     size("CVS", sizeof(CVS));  // 16
109     size("StaticInt", sizeof(StaticInt));  // 16
110     size("Method", sizeof(Method));  // 1
111     size("Son", sizeof(Son));  // 8
112     size("Son2", sizeof(Son2));  // 12
113     size("C", sizeof(C));  // 16
114     size("C2", sizeof(C2));  // 16
115 }

 

《原文如下》

1空類

1 class A {};

大小為1。 

類的實例化就是給每一個實例在內存中分配一塊地址。空類被實例化時,會由編譯器隱含的添加一個字節。所以空類的size為1。
2 虛函數

class A
{
  public:
    virtual void fun() {};
    virtual void fun2() {};
};

大小為4。 

當C++類中有虛函數的時候,會有一個指向虛函數表(V-table)的指針,所有的虛函數都在這個表中。指針大小為4,所以size為4。

在來看如下代碼:

class A
{
  public:
    char b;
    short c;
    int a;
};
class B
{
  public:
    char a;
    int c;
    short b;
};

考慮數據對齊,大小分別為 8 和 12。如果我們將int換成虛函數,會是什么結果呢?

class A
{
public:
  char b;
  short c;
  virtual void fun() {}
};
class B
{
public:
  char a;
  virtual void fun() {}
  short b;
};

大小分別為 8 8。 都是占4個字節,結果不一樣。 這是因為,為了效率問題,編譯器(gcc 和 微軟)一般會把虛指針放在類的內存空間的最前面的位置,不管虛函數聲明的位置。考慮對齊,大小都是 4 +1+1+2 = 8.

3 靜態數據成員

class A
{
public:
  char b;
  virtual void fun() {};
  static int c;
};

大小為8。 

靜態數據成員被編譯器放在程序的一個global data members中,它是類的一個數據成員,但不影響類的大小。不管這個類產生了多少個實例,還是派生了多少新的類,靜態數據成員只有一個實例。靜態數據成員,一旦被聲明,就已經存在。 考慮到數據對齊, 最終是8字節。

4 普通成員函數

class A
{
public:
  void fun() {};
};

大小為1。 

類的大小與構造函數,析構函數,普通成員函數無關。

5 普通單繼承

class A 
{
  int c;
};
class B : public A
{
  int a;
};

大小分別為4 和 8。 可以看到普通的繼承就是基類的大小+派生類自身的大小。注意數據對齊。 

注意:類的數據成員按其聲明順序加入內存,無訪問權限無關,只看聲明順序。

class A
{
  int a;
  char b;
};
class C : public A
{
  public:
  char c;
};

上面這段代碼,不同的編譯器結果不同,VS的結果是 8 和 12, GCC是8 和 8。VS中 相當於

class C
{
  A a;
  char c;
};

A的大小為8,對齊值為4, 則考慮總體對齊 8 + 1 + 3(padding) = 12。 

GCC 則是

class C
{
  int a;
  char b;
  char c;
};

結果為 4 + 1 + 1 + 2 = 8。【與實際執行有出入】

6 含虛函數的單繼承

class A
{
  virtual void fun () {}
};
class C : public A
{
public:
  virtual void fun2() {}
};

大小分別為4 和 4。派生類繼承了基類的虛指針,所以大小為4。

7 虛單繼承

class A
{
  virtual void fun () {}
};

class C : virtual public A
{
public:
  virtual void fun2() {}
};

這段代碼,VS和gcc結果不一樣。VS為 4 和 12。 gcc為4 和4。

8 普通多繼承

class A
{
  int a;
  char b;
};

class B
{
  char b;
};
class C : public A, public B
{
public:
  char c;
};

VS:8 1 12 

GCC:8 1 8
VS中相當於把A B當做整體看待, GCC則拆分整合。

9 虛函數多繼承

class A
{
  virtual void fun() {}
};

class B
{
  virtual void fun2() {}
};
class C : public A, public B
{
public:
  virtual void fun3() {}
};

結果為 4 4 8。分析:類A一個虛函數表,類B一個虛函數表,類C繼承了兩個虛函數表,並把自己的虛函數寫在了繼承順序中第一個虛函數表中。

10 虛繼承

class A
{
  virtual void fun() {}
};

class B
{
  virtual void fun2() {}
};
class C : virtual public A, virtual public B
{
public:
  virtual void fun3() {}
};

GCC: 4 4 8   VS:4 4 16


免責聲明!

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



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