C++類的大小——sizeof(class)
第一:空類的大小
class CBase
{
};
執行cout<<"sizeof(CBase)="<<sizeof(CBase)<<endl;
輸出
sizeof(CBase)=1;
為什麼空的什麼都沒有是1呢?
先了解一個概念:類的例項化,所謂類的例項化就是在記憶體中分配一塊地址,每個例項在記憶體中都有獨一無二的地址。同樣空類也會被例項化,所以編譯器會給空類隱含的新增一個位元組,這樣空類例項化之後就有了獨一無二的地址了。所以空類的sizeof為1。
第二:一般非空類大小
class CBase { int a; char *p; };
執行結果:
sizeof(CBase)=8
第三:有虛擬函式類
class CBase
{
public:
CBase(void);
virtual ~CBase(void);
private:
int a;
char *p;
};
執行結果:
sizeof(CBase)=12
“C++ 類中有虛擬函式的時候有一個指向虛擬函式的指標(vptr),在32位系統分配指標大小為4位元組”。
第四:有虛擬函式類的繼承
基類就是上面的了不寫了
class CChild : public CBase { public: CChild(void); ~CChild(void); private: int b; };
執行結果:
sizeof(CChild)=16;
可見子類的大小是本身成員變數的大小加上父類的大小。
另外:
1. 空類
class A
{
};
void main()
{
printf("sizeof(A): %d\n", sizeof(A));
getchar();
}
得到結果為:1。
類的例項化就是給每個例項在記憶體中分配一塊地址。空類被例項化時,會由編譯器隱含的新增一個位元組。所以空類的size為1。
2.虛擬函式
class A { virtual void FuncA(); virtual void FuncB(); };
得到結果:4
當C++ 類中有虛擬函式的時候,會有一個指向虛擬函式表的指標(vptr),在32位系統分配指標大小為4位元組。所以size為4.
3.靜態資料成員
class A
{
int a;
static int b;
virtual void FuncA();
};
得到結果:8
靜態資料成員被編譯器放在程式的一個global data members中,它是類的一個數據成員.但是它不影響類的大小,不管這個類實際產生了多少例項,還是派生了多少新的類,靜態成員資料在類中永遠只有一個實體存在。
而類的非靜態資料成員只有被例項化的時候,他們才存在.但是類的靜態資料成員一旦被宣告,無論類是否被例項化,它都已存在.可以這麼說,類的靜態資料成員是一種特殊的全域性變數.
所以該類的size為:int a型4位元組加上虛擬函式表指標4位元組,等於8位元組。
4.普通成員函式
class A
{
void FuncA();
}
結果:1
類的大小與它的建構函式、解構函式和其他成員函式無關,只已它的資料成員有關。
5.普通繼承
class A
{
int a;
};
class B
{
int b;
};
class C : public A, public B
{
int c;
};
結果為:sizeof(C) =12.
可見普通的繼承,就是基類的大小,加上派生類自身成員的大小。
6.虛擬繼承
class C : virtual public A, virtual public B
{
int c;
};
結果:16.
當存在虛擬繼承時,派生類中會有一個指向虛基類表的指標。所以其大小應為普通繼承的大小(12位元組),再加上虛基類表的指標大小(4個位元組),共16位元組。
類的大小問題實驗剖析:
1、空類:
C++編譯器強制給這種類插入一個預設成員,長度為1。如果有自定義的變數,變數將取代這個預設成員。
class A
{};
cout<<sizeof(A); //輸出1
2、只有一個char型
class A
{
char c;
};
cout<<sizeof(A); //輸出1
3、有5個char型
class A
{
char a,b,c,d,e;
};
cout<<sizeof(A); //輸出5
4、一個char型 + 一個int型:位元組對齊
class A
{
char c;
int a;
};
cout<<sizeof(A); //輸出8
5、2個char型 + 一個int型
class A
{
char c,d;
int a;
};
cout<<sizeof(A); //輸出8
6、5個char型 + 一個int型
class A
{
char c,d,e,f,g;
int a;
};
cout<<sizeof(A); //輸出12
7、1個char型 + 1個int型 + 2個char型
class A
{
char c;
int a;
char d,e;
};
cout<<sizeof(A); //輸出12
8、普通函式不佔空間
class A
{
void B(){ int d; }//0Byte
int C(){};
};
cout<<sizeof(A); //輸出1,等同於空類
9、虛擬函式 佔4個位元組:指向虛擬函式表的指標
class A
{
virtual void C(){}
};
cout<<sizeof(A); //輸出4
10、多個虛擬函式等同於1個虛擬函式
class A
{
virtual void C(){}
virtual void D(){}
};
cout<<sizeof(A); //輸出4
11、多繼承問題中sizeof
class b{};
class c :public b
{
virtual void fun() = 0;
};
class d :public b ,public c{};
cout<<sizeof(d); //輸出8,位元組對齊(b+c)
12、單繼承問題中sizeof
class b{};
class c :public b
{
virtual void fun() = 0;
};
class d :public c{};
cout<<sizeof(c); //輸出4
cout<<sizeof(d); //輸出4
13、靜態資料成員 和 成員函式 不佔空間
class A
{
static int a;
static int b(){};
};
cout<<sizeof(A); //輸出1
14、const資料變數佔空間 和 const成員函式不佔空間
class A
{
public:
const int b;
const int c;
virtual void f(){}
int d() const{}
int e() const{}
virtual void g(){}
A() :b(2), c(3)
{
}
};
cout<<sizeof(A); //輸出12= 4+4+4(多個虛擬函式算一個)
空類的大小
class Base
{
public:
Base();
~Base();
};
注意到我這裡顯示聲明瞭構造跟析構,但是sizeof(Base)的結果是1.
因為一個空類也要例項化,所謂類的例項化就是在記憶體中分配一塊地址,每個例項在記憶體中都有獨一無二的地址。同樣空類也會被例項化,所以編譯器會給空類隱含的新增一個位元組,這樣空類例項化之後就有了獨一無二的地址了。所以空類的sizeof為1。
而解構函式,跟建構函式這些成員函式,是跟sizeof無關的,也不難理解因為我們的sizeof是針對例項,而普通成員函式,是針對類體的,一個類的成員函式,多個例項也共用相同的函式指標,所以自然不能歸為例項的大小。
接著看下面一段程式碼
class Base
{
public:
Base();
virtual ~Base(); //每個例項都有虛擬函式表
void set_num(int num) //普通成員函式,為各例項公有,不歸入sizeof統計
{
a=num;
}
private:
int a; //佔4位元組
char *p; //4位元組指標
};
class Derive:public Base
{
public:
Derive():Base(){};
~Derive(){};
private:
static int st; //非例項獨佔
int d; //佔4位元組
char *p; //4位元組指標
};
int main()
{
cout<<sizeof(Base)<<endl;
cout<<sizeof(Derive)<<endl;
return 0;
}
結果自然是
12
20
Base類裡的int a;char *p;佔8個位元組。
而虛解構函式virtual ~Base();的指標佔4子位元組。
-其他成員函式不歸入sizeof統計。
Derive類首先要具有Base類的部分,也就是佔12位元組。
int d;char *p;佔8位元組
static int st;不歸入sizeof統計
所以一共是20位元組。
在考慮在Derive里加一個成員char c;
class Derive:public Base
{
public:
Derive():Base(){};
~Derive(){};
private:
static int st;
int d;
char *p;
char c;
};
這個時候,結果就變成了
12
24
一個char c;增加了4位元組,說明類的大小也遵守類似class位元組對齊,的補齊規則。
至此,我們可以歸納以下幾個原則:
1.類的大小為類的非靜態成員資料的型別大小之和,也就是說靜態成員資料不作考慮。
2.普通成員函式與sizeof無關。
3.虛擬函式由於要維護在虛擬函式表,所以要佔據一個指標大小,也就是4位元組。
4.類的總大小也遵守類似class位元組對齊的,調整規則。
5、不佔空間的有:普通函式,靜態資料成員,靜態成員函式。
6、無論多少個,只相當於一個所佔的空間:虛擬函式。
7、空類佔1個位元組。
8、既有字元型又有整型,要考慮位元組對齊。
9、普通資料成員、const資料成員佔空間;靜態成員不佔空間。
參考:
https://blog.csdn.net/u010069101/article/details/51045840
https://blog.csdn.net/hairetz/article/details/4171769
https://blog.csdn.net/zzhongcy/article/details/38361755