1. 程式人生 > 其它 >為什麼空類的大小不為0

為什麼空類的大小不為0

文章目錄

1. 空類

    所謂空類,意味著類中不攜帶任何資料。即該類中沒有非靜態成員函式、虛擬函式、虛基類等。理論上說,一個不攜帶任何資料的空類其所佔用的記憶體空間大小應該是零,因為它不需要儲存屬於任何附加物件的資料。

    實際情況果真如我們猜想的那樣空類的大小為零嗎?讓我們拭目以待。

//test.cpp
#include <iostream>
using namespace std;

class Base{
};

int main()
{
        cout<<"sizeof(Base): "
<<sizeof(Base)<<endl; return 0; }

    類Base是一個名副其實的空類,因為類內部不包含任何的成員和虛擬函式等。g++編譯該test.cpp程式(g++ test.cpp -o test),然後執行,得到的結果是:1。

在這裡插入圖片描述

    對於空類,它有一個虛擬佔位符成員,該成員大小為1位元組,這個佔位符成員保證了每個物件應具有唯一的地址。因此,Base類的不同物件其地址空間是不相同的。如下:

#include <iostream>
using namespace std;

class Base{
};

int main
() { cout<<"sizeof(Base): "<<sizeof(Base)<<endl; Base a, b; if(&a == &b) cout<<"The address is the same."<<endl; else cout<<"The address is different."<<endl;
cout<<"&a: "<<&a<<", "<<"&b: "<<&b<<endl; return 0; }

    現定義兩個Base類物件,分別是a和b。然後分別對兩個物件的地址進行判斷,若相等,則列印“The address is the same.”反之,則列印“The address is different.” 編譯執行,得到的列印結果如下:

在這裡插入圖片描述

    可看到,兩個物件所佔用的記憶體地址空間是不一樣的。

    若對於一個空類,其所有物件佔用的記憶體地址空間一樣,會出現什麼問題?如下示例所示,分別定義兩個指向Base類型別的指標變數,然後分別初始化。

Base *p1 = new Base;
Base *p2 = new Base;

delete p1;
delete p2;

    若各物件佔用的記憶體空間相同,那麼這裡delete p1、p2時候,會對同一記憶體空間釋放兩次,這是一個很嚴重的問題。

2. C++標準不允許空類大小為0

    C++標準保證任何類的大小至少為一位元組。並且標準規定,任何物件都不應該與另外一個物件具有相同的記憶體地址。這樣做的理由是:

    (1)保證了new始終會返回指向不同記憶體地址的指標。

    (2)避免被零除。例如,指標算術運算(其中許多有編譯器自動完成)涉及除以sizeof(類名)。如下示例所示,若空類Base大小為0,那麼下面demo將會導致段錯誤。由於C++標準規定空類不為0,所以下面的demo將正常執行,sizeof(b)結果是10。

#define ARRAY_SIZE(arr)   ( sizeof(arr) / sizeof(arr[0]) )
class Base{
};

Base b[10];
for(auto i = 0; i < ARRAY_SIZE(b); i++){
	do something; 
}

2.1 空的基類不會為派生類大小增1

    對於空類,其大小為1,那我現在宣告一個派生類,繼承於基類。派生類物件的大小是不是等於派生類大小+(空)基類大小(一位元組)呢?其實不然,空基類不會為派生類的大小加一。如下示例:

#include <iostream>
using namespace std;

class Base{
};

class SubBase : public Base
{
        char m_c;
};
int main()
{
        cout<<"sizeof(SubBase): "<<sizeof(SubBase)<<endl;
        return 0;
}

    從列印結果可看到,對於之類SubBase的大小仍然為1位元組,這裡的1位元組是子類的成員變數m_c的大小。所以空基類不會為派生類的大小增加一。
在這裡插入圖片描述