sizeof計算類的大小


1 sizeof一個空類

class A { };

cout<<sizeof(A)<<endl;//1

注:class A是一個空類型,它的實例不包含任何信息,本來求sizeof應該是0。

但當我們聲明該類型的實例的時候,它必須在內存中占有一定的空間,否則無法使用這些實例。

至於占用多少內存,由編譯器決定。Visual Studio 2008中每個空類型的實例占用一個byte的空間。

 

2 sizeof一個帶有構造和析構函數的類

class B

{

public:

  B() {}

   ~B() {}

};

cout<<szieof(B)<<endl;//1

  

注:class B在class A的基礎上添加了構造函數和析構函數。

       由於構造函數和析構函數的調用與類型的實例無關(調用它們只需要知道函數地址即可),在它的實例中不需要增加任何信息。

       所以sizeof(B)和sizeof(A)一樣,在Visual Studio 2008中都是1。

 

3 sizeof一個帶有虛函數的類

class C

{

public:

  C() {}

  virtual ~C() {}

};

cout<<sizeof(C)<<endl;//4

  

注:class C在class B的基礎上把析構函數標注為虛擬函數。C++的編譯器一旦發現一個類型中有虛擬函數,

       就會為該類型生成虛函數表,並在該類型的每一個實例中添加一個指向虛函數表的指針。

       在32位的機器上,一個指針占4個字節的空間,因此sizeof(C)是4。

       C++標准規定類的大小不為0,空類的大小為1,當類不包含虛函數和非靜態數據成員時,其對象大小也為1。

       如果在類中聲明了虛函數(不管是1個還是多個),那么在實例化對象時,編譯器會自動在對象里安插一個指針指向虛函數表VTable,

       在32位機器上,一個對象會增加4個字節來存儲此指針,它是實現面向對象中多態的關鍵。而虛函數本身和其他成員函數一樣,是不占用對象的空間的。

 

4 sizeof一個帶有成員變量的類

class D {

    char ch;

    void func() { }

};

class E {

    char ch1; //占用1字節

    char ch2; //占用1字節

    virtual void func() { }

};
class F {

    int in;

    virtual void func() { }

};

cout << "D的大小"<< sizeof(D) << endl;//1
cout << "E的大小" << sizeof(E) << endl;//8
cout << "F的大小" << sizeof(E) << endl;//8

 注:類和結構體一樣,需要考慮數據對齊和補齊規則

5 sizeof簡單繼承類

class COneMember

{

public:

    COneMember(int iValue = 0){m_iOne = iValue;};

private:

    int m_iOne;

};

內存結構:00 00 00 00 //m_iOne

class CTwoMember:public COneMember

{

private:

    int m_iTwo;

};

內存結構:

00 00 00 00 //m_iOne

CC CC CC CC //m_iTwo

注:子類成員接在父類成員之后

class CThreemember:public CTwoMember

{

public:

    CThreemember(int iValue=10) {m_iThree = iValue;};

private:

    int m_iThree;

};
內存結構:
00 00 00 00 //m_iOne

CC CC CC CC //m_iTwo

0A 00 00 00 //m_iThree

注:孫類成員接在子類之后,再再繼承就依此類推了。

cout<<sizeof(COneMember)<<endl;//4
cout<<sizeof(CTwoMember)<<endl;//8
cout<<sizeof(CThreeeMember)<<endl;//12    

 

6 sizeof多重繼承類

class ClassA

{

public:

    ClassA(int iValue=1){m_iA = iValue;};

private:

    int m_iA;

};

 

class ClassB

{

public:

    ClassB(int iValue=2){m_iB = iValue;};

private:

    int m_iB;

};

 

class ClassC

{

public:

    ClassC(int iValue=3){m_iC = iValue;};

private:

    int m_iC;

};

 

class CComplex :public ClassA, public ClassB, public ClassC

{

public:

    CComplex(int iValue=4){m_iComplex = iValue;};

private:

    int m_iComplex;

};

內存結構:
01 00 00 00  //A

02 00 00 00  //B

03 00 00 00  //C

04 00 00 00  //Complex

注:也是父類成員先出現在前邊,我想這都足夠好理解。

cout<<sizeof(CComplex )<<endl;//16

  

7 sizeof 虛繼承的類

class CTwoMember:virtual public COneMember

{

private:

    int m_iTwo;

};

內存結構:

E8 2F 42 00 //指針,指向一個關於偏移量的數組,且稱之虛基類偏移量表指針

CC CC CC CC // m_iTwo

00 00 00 00 // m_iOne(虛基類數據成員)

長度:12

注:virtual讓長度增加了4,其實是多了一個指針。

  

8 sizeof一個閉合虛繼承類

內存結構:

14 30 42 00 //ClassB的虛基類偏移量表指針

02 00 00 00 //m_iB

C4 2F 42 00 //ClassC的虛基類偏移量表指針

03 00 00 00 //m_iC

04 00 00 00 //m_iComplex

01 00 00 00 //m_iA

長度:24

注:虛基類的成員m_iA只出現了一次,而且是在最后邊。虛繼承利用一個“虛基類偏移量表指針”來使得虛基類即使被重復繼承也只會出現一次。

 

9 sizeof一個帶有static數據成員的類

class CStaticNull

{

public:

    CStaticNull(){printf("Construct/n");}

    ~CStaticNull(){printf("Desctruct/n");}

    static void Foo(){printf("Foo/n");}

    static int m_iValue;

};

內存結構:和空類相同
長度:1
注:static成員不會占用類的大小,static成員的存在區域為靜態區,可認為它們是“全局”的,只是不提供全局的訪問而已,這跟C的static其實沒什么區別。

  

10 帶有一個虛函數的空類

class CVirtualNull

{

public:

    CVirtualNull(){printf("Construct/n");}

    ~CVirtualNull(){printf("Desctruct/n");}

    virtual void Foo(){printf("Foo/n");}

};

內存結構:
00 31 42 00 //指向虛函數表的指針(虛函數表后面簡稱“虛表”)

00423100:(虛表)
41 10 40 00 //指向虛函數Foo的指針

00401041:
E9 78 02 00 00 E9 C3 03 … //函數Foo的內容(看不懂)

長度:4
注:虛函數的類長度就增加了4,這個4其實就是個指針,指向虛函數表的指針,上面這個例子中虛表只有一個函數指針,值就是“0x00401041”,指向的這個地址就是函數的入口了

  

11 sizeof一個繼承帶虛函數的類

class CVirtualDerived : public CVirtualNull

{

public:

    CVirtualDerived(){m_iVD=0xFF;};

    ~CVirtualDerived(){};

private:

    int m_iVD;

};

長度:8
內存結構:
3C 50 42 00 //虛表指針
FF 00 00 00 //m_iVD

0042503C:(虛表)
23 10 40 00 //指向虛函數Foo的指針,如果這時候創建一個CVirtualNull對象,會發現它的        虛表的內容跟這個一樣

注:由於父類帶了虛函數,子類就算沒有顯式聲明虛函數,虛表還是存在的,虛表存放的位置跟父類不同,但內容是同的,也就是對父類虛表的復制。

  

12 sizeof子類帶虛函數,基類帶虛函數

class CVirtualDerived: public CVirtualNull

{

public:

    CVirtualDerived(){m_iVD=0xFF;};

    ~CVirtualDerived(){};

    virtual void Foo2(){printf("Foo2/n");};

private:

    int m_iVD;

};

內存結構:
24 61 42 00 //虛表指針
FF 00 00 00 //m_iVD

00426124:(虛表)
23 10 40 00
50 10 40 00

長度:8
注:虛表還是只有一張,不會因為增加了新的虛函數而多出另一張來,新的虛函數的指針將添加在復制了的虛表的后面。

  


免責聲明!

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



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