c++基礎之空類的大小
技術標籤:C/C++基礎
初學者在學習面向物件的程式設計語言時,或多或少的都些疑問,我們寫的程式碼與最終生編譯成的程式碼卻 大相徑庭,我們並不知道編譯器在後臺做了什麼工作.這些都是由於我們僅停留在語言層的原因,所謂語言層就是教會我們一些基本的語法法則,但不會告訴我們為什麼這麼做?今天和大家談的一點感悟就是我在學習程式設計過程中的一點經驗,是編譯器這方面的一個具體功能.
首先:我們要知道什麼是類的例項化,所謂類的例項化就是在記憶體中分配一塊地址
那我們先看看一個例子:
#include<iostream>
using namespace std;
class a {};
class b{ };
class c :public a
{
virtual void fun() = 0;
};
class d :public b, public c
{
};
int main()
{
cout << "sizeof(a) = " << sizeof(a) << endl;
cout << "sizeof(b) = " << sizeof(b) << endl;
cout << "sizeof(c) = " << sizeof (c) << endl;
cout << "sizeof(d) = " << sizeof(d) << endl;
getchar();
return 0;
}
結果:
為什麼會出現這種結果呢?初學者肯定會很煩惱是嗎?
類a,b明明是空類,它的大小應該為為0,為什麼 編譯器輸出的結果為1呢?
這就是我們剛才所說的例項化的原因(空類同樣可以被例項化),每個例項在記憶體中都有一個獨一無二的地址,為了達到這個目的,編譯器往往會給一個空類隱含的加一個位元組,這樣空類在例項化後在記憶體得到了獨一無二的地址.所以a,b的大小為1
《深入理解C++物件模型》這本書是這樣解釋的:一個空類事實上並不是空的,它有一個隱晦的 1byte ,那是被編譯器安插進去的一個char。這使得這個 class 的兩個不同的物件得以在記憶體中配置獨一無二的地址。
簡而言之一個類的例項化物件有著它自己的獨一無二的地址,而地址是代表著一段記憶體大小,假如一個空類的空間大小也為0,則我們不能為它分配記憶體,不能得到它的地址,因此編譯器會為空類新增一個隱晦的char用以來標識空類的例項化物件。
而類c是由類a派生而來,它裡面有一個純虛擬函式,由於有虛擬函式的原因,有一個指向虛擬函式的指標(vptr),在32位的系統分配給指標的大小為4個位元組,所以最後得到c類的大小為4.
類d的大小更讓初學者疑惑吧,類d是由類b,c派生邇來的,它的大小應該為二者之和5,為什麼卻是8 呢?這是因為為了提高例項在記憶體中的存取效率.類的大小往往被調整到系統的整數倍.並採取就近的法則,裡哪個最近的倍數,就是該類的大小,所以類d的大小為8個位元組.
在看個例子:
#include <iostream>
#include <string>
using namespace std;
class a{
private:
int m_data1;
};
class b{
private:
int m_data2;
static int m_data3;
};
int b::m_data3 = 0;
void main()
{
cout << "sizeof(a)=" << sizeof(a) << endl;
cout << "sizeof(b)=" << sizeof(b) << endl;
system("pause");
}
結果:
為什麼類b多了一個數據成員,卻大小和類a的大小相同呢?因為:類b的靜態資料成員被編譯器放在程式的一個global data members中,它是類的一個數據成員.但是它不影響類的大小,不管這個類實際產生 了多少例項,還是派生了多少新的類,靜態成員資料在類中永遠只有一個實體存在,而類的非靜態資料成員只有被例項化的時候,他們才存在.但是類的靜態資料成員一旦被宣告,無論類是否被例項化,它都已存在.可以這麼說,類的靜態資料成員是一種特殊的全域性變數.
所以a,b的大小相同.
接下來看看建構函式、解構函式、普通函式:
#include<iostream>
using namespace std;
class A{
public:
A(int a)
{
a = x;
}
void f(int x)
{
cout << x << endl;
}
~A()
{
}
private:
int x;
int g;
};
void main()
{
A s(10);
s.f(10);
cout << "sozeof(a) = " << sizeof(A) << endl;
system("pause");
}
結果:
它們的結果均相同,可以看出類的大小與它當中的建構函式,解構函式,以及其他的成員函式無關,只與它當中的成員資料有關.