sizeof(類)


類的大小是什么?確切的說,類只是一個類型定義,它是沒有大小可言的。 用sizeof運算符對一個類型名操作,得到的是具有該類型實體的大小。首先:我們要知道什么是類的實例化,所謂類的實例化就是在內存中分配一塊地址

用sizeof對類名操作,得到的結果是該類的對象在存儲器中所占據的字節大小,由於靜態成員變量不在對象中存儲,因此這個結果等於各非靜態數據成員(不包括成員函數)的總和加上編譯器額外增加的字節。后者依賴於不同的編譯器實現,C++標准對此不做任何保證。

確定類大小的幾個原則:

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

下面分情況討論:

編譯器:vs2013

1. 空類

#include <iostream> 
using namespace std;

class A{};

int main()
{
    cout << sizeof(A) << endl;
    system("pause");
}

 輸出:1

C++標准規定類的大小不為0,空類的大小為1,當類不包含虛函數和非靜態數據成員時,其對象大小也為1。這就是我們剛才所說的實例化的原因(空類同樣可以被實例化),每個實例在內存中都有一個獨一無二的地址,為了達到這個目的,編譯器往往會給一個空類隱含的加一個字節,這樣空類在實例化后在內存得到了獨一無二的地址

 

2. 簡單類

使用sizeof求這種簡單類,結果和求結構體的sizeof是一樣的,需要考慮偏移和對齊。要注意的是static變量不屬於類的一部分,如果類中定義了static變量,求sizeof時可以忽略它們。

#include <iostream> 
using namespace std;

class A
{
    int a;
};
class B
{
    char a;
};
class C
{
    int a;
    char b;
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    cout << sizeof(C) << endl;
    system("pause");
}

輸出:

4  sizeof(int)

1  sizeof(char)

8  sizeof(int) + sizeof(char)(考慮對齊)

 

3. 帶虛函數的類

虛函數放在虛表中,類中定義了虛函數,需要存放一個指向虛表的指針

如果在類中聲明了虛函數(不管是1個還是多個),那么在實例化對象時,編譯器會自動在對象里安插一個指針指向虛函數表VTable,在32位機器上,一個對象會增加4個字節來存儲此指針,它是實現面向對象中多態的關鍵。而虛函數本身和其他成員函數一樣,是不占用對象的空間的

#include <iostream> 
using namespace std;

class A
{
    int a;
    virtual void fun(){}
    virtual void fun1(){}
    virtual void fun3(){}
};

int main()
{
    cout << sizeof(A) << endl;
    system("pause");
}

輸出

8  sizeof(int) + sizeof(虛表指針)

 

4. 普通繼承(父類不含虛函數)

#include <iostream> 
using namespace std;

class A
{
    int num;
    char str;
};
class B : public A
{
    char str2;
    int num2;
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    system("pause");
}

輸出:

8   sizeof(類A)

16  sizeof(類A) + sizeo(類B)

一般來說,普通繼承的空間計算結果應當是sizeof(基類)+sizeof(派生類),然后考慮對齊,內存空間必須是類中數據成員所占用最大空間的整數倍。不過這是一般情況,具體怎么算要看編譯器,codeblocks把類B看成12,因為把str2和str放在一起了

 

5.普通繼承(父類含虛函數)

#include <iostream> 
using namespace std;

class A
{
    int num;
    virtual void fun(){}
};
class B : public A
{
    int num2;
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    system("pause");
}

輸出:

8   sizeof(類A)

12  sizeof(類A) + sizeo(類B)

 

6. 普通繼承(含虛函數的子類普通繼承含虛函數的父類)

這個要注意的一點是,雖然子類和父類都包含虛函數, 但它們存放於同一個虛表中,因此只需要一個指針

#include <iostream> 
using namespace std;

class A
{
    int num;
    virtual void fun(){}
};
class B : public A
{
    int num2;
    virtual void fun1(){}
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    system("pause");
}

 

輸出:

8   sizeof(int) + sizeof(指針)

12  sizeof(int) + sizeof(int) + sizeof(指針)  (繼承后只有一個虛表)

 

7. 子類虛繼承父類

sizeof(子類)=sizeof(基類)+sizeof(虛表指針)+sizeof(子類數據成員)  此外,如果子類和基類都有虛函數,各自用各自的虛表

#include <iostream> 
using namespace std;

class A
{
    int num;
};
class B : virtual public A
{
    int num2;
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    system("pause");
}

輸出:

4

12  sizeof(A) + sizeof(B) + sizeof(虛繼承指針)

 

#include <iostream> 
using namespace std;

class A
{
    int num;
    virtual void fun(){}
};
class B : virtual public A
{
    int num2;
    virtual void fun1(){}
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    system("pause");
}

輸出:

8

20  sizeof(A) + sizeof(B) + sizeof(虛繼承指針) +  sizeof(A類虛表指針) +  sizeof(B類虛表虛指針)

 

8. 多重虛繼承

虛繼承存在的意義就是為了減少內存開銷和二義性,實現對象共享。

#include <iostream> 
using namespace std;

class A
{
    int num;
};
class B : virtual public A
{
    int num2;
};

class C : virtual public A
{
    int num3;
};

class D : public B, public C
{
    int num4;
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    cout << sizeof(C) << endl;
    cout << sizeof(D) << endl;
    system("pause");
}

 

輸出:

4

12

12

24  

D中包含a,b,c,d四個數據成員,還包含兩個指向虛基類A的指針,這種情況下,VS和CB都沒有將兩個指針合為一個。這種情況也可以這樣考慮,sizeof(D)=sizeof(B)+sizeof(C),但由於是虛繼承,虛基類A中數據成員a只需要保留一份,而我們算了兩次,所以還需要減去A的數據成員,所以公式應當是sizeof(D)=sizeof(D的非靜態數據成員) + sizeof(B)+sizeof(C)-sizeof(A的非靜態數據成員)。

 

參考資料:http://blog.csdn.net/szchtx/article/details/10254007


免責聲明!

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



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