1. 程式人生 > 其它 >c++基礎之空類的大小

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");
}

結果:
在這裡插入圖片描述

它們的結果均相同,可以看出類的大小與它當中的建構函式,解構函式,以及其他的成員函式無關,只與它當中的成員資料有關.