C++類的大小


一個空類class A{};的大小為什么是1,因為如果不是1,當定義這個類的對象數組時候A objects[5]; objects[0]和objects[1]就在同一個地址處,就無法區分。

單繼承

#include<iostream>
using namespace std;
class A
{
public:
    virtual void aa(){}
private:
    char k[3];
};

class B: public A
{
public:
    virtual void bb(){}
};

int main()
{
    cout<<"A's size is "<<sizeof(A)<<endl;
    cout<<"B's size is "<<sizeof(B)<<endl;
    return 0;
}

vs和gcc下
執行結果:A's size is 8
              B's size is 8

說明:有虛函數的類有個virtual table(虛函數表),里面包含了類的所有虛函數,類中有個virtual table pointers,通常成為vptr指向這個virtual table,占用4個字節的大小。成員類B public繼承於A,類B的虛函數表里實際上有兩個虛函數A::aa()和B::bb(),類B的大小等於char k[3]的大小加上一個指向虛函數表指針vptr的大小,考慮內存對齊為8。

#include<iostream>
using namespace std;
class A
{
public:
    virtual void aa(){}
private:
    char k[3];
};

class B: public A
{
public:
    //virtual void bb(){}
};

int main()
{
    cout<<"A's size is "<<sizeof(A)<<endl;
    cout<<"B's size is "<<sizeof(B)<<endl;
    return 0;
}

vs和gcc下
執行結果:A's size is 8
              B's size is 8
說明:類B看上去沒有虛函數,但實際上它有,只是沒有重寫,因為public繼承,所以有從A繼承過來的虛函數A::aa(),實際上類A和類B的虛函數表里的函數都是A::aa()。

#include<iostream>
using namespace std;
class A
{
public:
    virtual void aa(){}
    virtual void aa2(){}
private:
    char k[3];
};

class B: public A
{
public:
    virtual void bb(){}
    virtual void bb2(){}
};

int main()
{
    cout<<"A's size is "<<sizeof(A)<<endl;
    cout<<"B's size is "<<sizeof(B)<<endl;
    return 0;
}

vs和gcc下
執行結果:A's size is 8
              B's size is 8

說明:一個類里若有虛函數,無論有多少個虛函數都只有一個指向虛表的指針,虛表中的每一個表項保存着一個虛函數的入口地址。當調用虛函數時,先找到虛表中它對應的表項,找到入口地址再執行。對於直接單繼承,無論類B中有無虛函數,由於它繼承了類A,且類A里含有虛函數,因此如果類B有虛函數,那么它和類A的是在同一個屬於類B的虛表里,這張虛表的虛函數為A::aa()、A::aa2()、B::bb()、B::bb2()。注意:類A里的私有成員在類B里仍占有內存。

多繼承

#include<iostream>
using namespace std;
class A
{
public:
    virtual void aa(){}
    virtual void aa2(){}
private:
    char k[3];
};

class B
{
public:
    virtual void bb(){}
    virtual void bb2(){}
};

class C: public A,public B
{
public:
    virtual void aa(){} //重寫了A的aa()
    virtual void cc(){}
};

int main()
{
    cout<<"A's size is "<<sizeof(A)<<endl;
    cout<<"B's size is "<<sizeof(B)<<endl;
    cout<<"C's size is "<<sizeof(C)<<endl;
    return 0;
}

vs和gcc下
執行結果:A's size is 8
          B's size is 4
          B's size is 12

說明:類A和B的大小就不解釋了,參照上面。類C多重繼承於A和B(有虛函數覆蓋),那么類C的大小是多少?先看成員變量,有一個繼承A的char k[3]。再看虛函數,類C的中虛函數是怎么分布的?先有一個虛函數表,里面有繼承於類A的虛函數和C自己的虛函數(C::aa(), A::aa2(), C::cc()),如果C沒有重寫aa(),那么第一個虛函數就是A::aa(),接着有第二張虛函數表是繼承包含類B的虛函數B::bb()、B::bb2()(類C沒有重寫B的虛函數)。總的大小就是2張虛表的大小(也即兩個虛函數指針的大小)8字節加上3字節的k[3],考慮內存對齊,就是12字節。

虛繼承

#include<iostream>
using namespace std;
class A
{
public:
    virtual void aa(){}
private:
    char k[3];
};

class B: virtual public A
{
public:
    //virtual void bb(){}
};

int main()
{
    cout<<"A's size is "<<sizeof(A)<<endl;
    cout<<"B's size is "<<sizeof(B)<<endl;
    return 0;
}

vs和gcc下
執行結果:A's size is 8
              B's size is 12
說明:類B里包含,繼承的char k[3],繼承的虛函數,類B的虛函數表里有A::aa(),因為是虛繼承,還有一個指向父類的指針,該指針為指向虛基類的指針(Pointer to virtual base class)。考慮內存對齊,總大小為12。

#include<iostream>
using namespace std;
class A
{
public:
    virtual void aa(){}
private:
    char k[3];
};

class B: public virtual A
{
public:
    virtual void bb(){}
};

int main()
{
    cout<<"A's size is "<<sizeof(A)<<endl;
    cout<<"B's size is "<<sizeof(B)<<endl;
    return 0;
}

VS執行結果:A's size is 8
                  B's size is 16

gcc執行結果:A's size is 8
                  B's size is 12

說明:對於虛繼承,類B虛繼承類A時,首先要通過加入一個指針來指向父類A,該指針被稱為虛基類指針。然后包含從父類繼承過來的3個char,再加上一個虛函數指針。考慮內存對齊,在gcc下結果是4+4+4=12。在VS下,結果是16,why?這一題和上一題區別只是在類B中添加了一個虛函數,但是兩個題目中類B都有虛函數表。在VS下調試查看匯編代碼,發現多出來的4字節什么也沒有。

關於C++虛函數,可以看《C++虛函數表解析》:http://blog.csdn.net/haoel/article/details/1948051

 


免責聲明!

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



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