虛指針的對齊_第二門課_第一週_作業

喜歡的朋友可以關注收藏一下:  http://blog.csdn.NET/qq_31201973

本文如有錯誤,請及時私信我。

原版要求:

分別給出下面的類型Fruit和Apple的類型大小(即對象size),並通過畫出二者對象模型圖以及你的測試來解釋該size的構成原因。

 

class Fruit{test
   int no;
   double weight;
   char key;
public:
   void print() {   }
   virtual void process(){   }
};
   
class Apple: public Fruit{
   int size;
   char type;
public:
   void save() {   }
   virtual void process(){   }
};

 

Fruit的類型大小(即對象size):32

Apple的類型大小(即對象size):40

(win10,vs2013編譯有效)

對象模型圖(字節對齊,虛基類表指針字節對齊):

 

上圖是我根據測試得出的對齊模型表

 

在c++對象模型中會有對齊規則:

每個特定平臺上的編譯器都有自己的默認“對齊係數”(也叫對齊模數)。程序員可以通過預編譯命令#pragma pack(n),n=1,2,4,8,16 來改變這一系數,其中的n就是你要指定的“對齊係數”。
規則:
1、數據成員對齊規則:結構(struct)(或聯合(union))的數據成員,第一個數據成員放在offset爲0的地方,以後每個數據成員的對齊 按照#pragma pack指定的數值和這個數據成員自身長度中,比較小的那個進行。
2、結構(或聯合)的整體對齊規則:在數據成員完成各自對齊之後,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的 數值和結構(或聯合)最大數據成員長度中,比較小的那個進行。
3、當#pragma pack的n值等於或超過所有數據成員長度的時候,這個n值的大小將不產生任何效果。

除了這三條規則之外虛指針會單獨對齊:

    類Fruit有虛函數,所以會有一個隱藏的成員,虛函數表指針,放在類對象的最開始的地方,因爲類Fruit的最大對齊參數就是隱藏成員本身的對齊參數8了,所以在後面補充4個字節。然後就是成員變量no,後面是weight對齊參數是8,所以在no後面補充四個字節,然後是key,對齊係數是1,所以緊跟在後面。因爲Fruit本身也要自身對齊,按照它的成員中最大的那個有效對齊作爲自己的自身對齊,也就是weight,所以Fruit本身要按照8字節對齊,所以在key後面要填充7個字節才滿足對齊規則。

sizeof(Fruit)=4+4+4+4+8+1+7=32            √

      類Apple有虛函數,所以會有一個隱藏的成員,虛函數表指針,放在類對象的最開始的地方,因爲類Apple的最大對齊參數就是隱藏成員本身的對齊參數8了,所以在vptr後面補充4個字節。然後就是成員變量no,後面是weight對齊參數是8,所以在no後面補充四個字節,然後是key,對齊係數是1,所以緊跟在後面,然後是size,對齊係數是4所以補充3個字節,然後是type對齊係數是1緊跟在後面。因爲Apple本身也要自身對齊,按照它的成員中最大的那個有效對齊作爲自己的自身對齊,也就是weight,所以Fruit本身要按照8字節對齊,所以在key後面要填充7個字節才滿足對齊規則。

sizeof(Apple)=4+4+4+4+8+1+3+4+1+7=40        √

測試代碼:

 

 

 

#include<iostream>
using namespace std;

class Fruit{
protected:
	int no;
	double weight;
	char key;
public:
	void print() {
		cout << "sizeof(f1.no)=" << sizeof(this->no) << endl;
		cout << "sizeof(f1.weight)=" << sizeof(this->weight) << endl;
		cout << "sizeof(f1.key)=" << sizeof(this->key) << endl;
	}
	const int* get_no() const { return &no; }
	const double* get_weight() const { return &weight; }
	const char* get_key() const { return &key; }
	virtual void process(){   }  
};

class Apple : public Fruit{
protected:
	int size;
	char type;
public:
	void print() {
		cout << "sizeof(a1.no)=" << sizeof(this->no) << endl;
		cout << "sizeof(a1.weight)=" << sizeof(this->weight) << endl;
		cout << "sizeof(a1.key)=" << sizeof(this->key) << endl;
		cout << "sizeof(a1.no)=" << sizeof(this->size) << endl;
		cout << "sizeof(a1.weight)=" << sizeof(this->type) << endl;
	}
	void save() {   }
	const int* get_size() const { return &size; }
	const char* get_type() const { return &type; }
	virtual void process(){   }
};

int main()
{
	Fruit f1;
	Apple a1;
	int* pf1 = (int*)&f1;
	int* pa1 = (int*)&a1;
	cout <<"Fruit類vptr的大小:"<< sizeof(pf1) << endl;
	f1.print();
	cout << "Fruit類大小:sizeof(f1)=" << sizeof(f1) << endl;
	cout << "Fruit類vptr的地址:" << pf1 << endl;
	cout << "Fruit類no的地址:" << f1.get_no() << endl;
	cout << "Fruit類weight的地址:" << f1.get_weight() << endl;
	cout << "Fruit類key的地址:" << (int*)(f1.get_key()) << endl;
	cout << "Fruit類vtbl的地址:" << (int*)(*pf1) << endl;
	cout << "Fruit::process()的地址:" << (int*)*((int*)(*pf1)) << endl;
	cout << "——————————————————————————" << endl;

	cout << "Apple類vptr的大小:" << sizeof(pa1) << endl;
	a1.print();
	cout << "Apple類大小:sizeof(a1)=" << sizeof(a1) << endl;
	cout << "Apple類vptr的地址:" << pa1 << endl;
	cout << "Apple類no的地址:" << a1.get_no() << endl;
	cout << "Apple類weight的地址:" << a1.get_weight() << endl;
	cout << "Apple類key的地址:" << (int*)(a1.get_key()) << endl;
	cout << "Apple類size的地址:" << a1.get_size() << endl;
	cout << "Apple類type的地址:" << (int*)(a1.get_type()) << endl;
	cout << "Apple類vtbl的地址:" << (int*)(*pa1) << endl;
	cout << "Apple::process()的地址:" << (int*)*((int*)(*pa1)) << endl;



	getchar();
	return 0;
}


測試結果:

 

 

 

參考資料:

1. http://blog.csdn.net/haoel/article/details/1948051/

2. http://blog.csdn.net/chengonghao/article/details/51679743

3.http://blog.csdn.net/hairetz/article/details/4084088

4. http://www.jb51.net/article/36903.htm

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章