1. 程式人生 > >2.2 C++物件結構的發展和演化-C++類的物件模型分析

2.2 C++物件結構的發展和演化-C++類的物件模型分析

一、非靜態成員變數(普通成員變數)跟著類的物件走(存在物件內部),也就是每個類物件都有自己的成員變數。

示例程式碼:

#include <iostream>
using namespace std;
class A
{
public:
	int a = 100; 
};

//類物件所佔的空間
int main()
{
	A aobj;
	int ilen = sizeof(aobj);
	cout << ilen << endl;

	getchar();
	return 0;
}


除錯:

找到物件 aobj的地址:

黏貼到記憶體中:

記憶體地址  64 00 00 00 ,這四個位元組即為 物件aobj的記憶體地址,十六進位制 64 轉化為十進位制為數值 100,即    int a = 100; 

二、靜態成員變數跟類的物件沒有什麼關係,所以肯定不會儲存在物件內部,是儲存在物件外面(表示所佔用的記憶體空間和類物件無關)的。

示例程式碼:

#include <iostream>
using namespace std;
class A
{
public:
	static int a; 
	static int b;
};

int main()
{
	A aobj;
	int ilen = sizeof(aobj);
	cout << ilen << endl;

	getchar();
	return 0;
}


輸出:

三、 成員函式:不管靜態的還是非靜態的,全部儲存在類物件之外。所以不管幾個成員函式,不管是否是靜態的成員函式,物件的sizeof()都是不增加的。

示例程式碼:

#include <iostream>
using namespace std;
class A
{
public:
	static void sfunc() {};  //靜態成員函式
	void myfunc() {};   //普通成員函式
};

int main()
{
	A aobj;
	int ilen = sizeof(aobj);
	cout << ilen << endl;

	getchar();
	return 0;
}


輸出:

四、虛擬函式:不管幾個虛擬函式,sizeof()都是多了4個位元組。

示例程式碼:

#include <iostream>
using namespace std;
class A
{
public:
	virtual void vfrandfunc1() {}; //虛擬函式 1
	virtual void vfrandfunc21() {}; //虛擬函式2 
};

int main()
{
	A aobj;
	int ilen = sizeof(aobj);
	cout << ilen << endl;

	getchar();
	return 0;
}


 輸出:

結果分析: 

    (4.1)類裡只要有一個虛擬函式(或者說至少有一個虛擬函式),這個類 會產生一個 指向 虛擬函式 的指標。       有兩個虛擬函式,那麼這個類 就會產生兩個指向虛擬函式的指標。     類本身  指向虛擬函式的 指標(一個或者一堆)要有地方存放,存放在一個表格裡,這個表格我們就稱為“虛擬函式表(virtual table【vtbl】)”;      這個虛擬函式表一般是儲存在可執行檔案中的,在程式執行的時候載入到記憶體中來。     虛擬函式表是基於類的,跟著類走的;

    (4.2)說說類物件,這四個位元組的增加,其實是因為虛擬函式的存在;因為有了虛擬函式的存在,導致系統往類物件中添加了一個指標,      這個指標正好指向這個虛擬函式表,很多資料上把這個指標叫vptr;這個vptr的值由系統在適當的時機(比如建構函式中通過增加額外的程式碼來給值);

五、小結:(對於類中)

    (1)靜態資料成員不計算在類物件sizeof()內;     (2)普通成員函式和靜態成員函式不計算在類物件的sizeof()內     (3)虛擬函式不計算在類物件的sizeof()內,但是虛擬函式會讓類物件的sizeof()增加4個位元組以容納虛擬函式表指標。     (4)虛擬函式表[vtbl]是基於類的(跟著類走的,跟物件沒關係,不是基於物件的);     (5)如果有多個數據成員,那麼為了提高訪問速度,某些編譯器可能會將資料成員之間的記憶體佔用比例進行調整。(記憶體位元組對齊)

例如:

class A //由於位元組對齊,共佔用8個位元組
{
public:
	char a; //1位元組,由於位元組對齊,編譯器會分配給4個位元組
	int b;  //4位元組
};

  (6)不管什麼型別指標char *p,int *q;,該指標佔用的記憶體大小是固定的 例如:

int ilen2 = sizeof(char *); //佔用4個位元組(linux下佔用8個位元組)
int ilen3 = sizeof(int *);  //佔用4個位元組

六、程式設計實驗:

#include <iostream>
using namespace std;

class myobject
{
public:
	myobject() {};//建構函式,不佔物件空間
	virtual ~myobject() {}; //解構函式,產生虛擬函式表,佔4個位元組       
	float getvalue() const //普通成員函式不佔物件位元組
	{
		return m_value;
	}

	static int s_getcount() //靜態成員函式,不佔位元組 
	{
		return ms_scount;
	}

	virtual void vfrandfunc() {}; //虛擬函式,只算一個虛擬函式的4位元組(解構函式) 

protected:
	float m_value; //普通成員變數,佔4位元組
	static int ms_scount; //靜態成員變數,不佔位元組,跟著類走
};

int main()
{
	
	myobject obj;
	int ilen = sizeof(obj);
	cout << ilen << endl; 
	getchar();
	return 0;
}

輸出:

 

結果分析:

   成員變數m_value佔4位元組,虛擬函式表指標佔4位元組。

七、總結類物件大小的組成:     (1)非靜態成員變數所佔的記憶體總量以及這些成員變數之間內才能位元組對齊所額外佔用的記憶體;     (2)若有虛擬函式,則會產生虛擬函式表指標(vptr)。

八、C++類的物件模型:

本文為聽課筆記,課程出處: