1. 程式人生 > >深度探索C++物件模型(2)——物件(2)——this指標調整

深度探索C++物件模型(2)——物件(2)——this指標調整

this指標調整

首先看程式碼示例:

#include <iostream>
using namespace std;

class A {
public:
	int a;
	A()
	{
		printf("A::A()的this指標是:%p!\n",this);
	}

	void funA()
	{
		printf("A::funA()的this指標是:%p!\n",this);
	}
	virtual void fun()
	{
	
	}
};

class B
{
public:
	int b;
	B()
	{
		printf("B::B()的this指標是:%p!\n", this);
	}

	void funB()
	{
		printf("B::funB()的this指標是:%p!\n", this);
	}
};

class C: public A,public B     //注意繼承順序,決定了後面的記憶體佈局
{
public:
	int c;
	C()
	{
		printf("C::C()的this指標是:%p!\n", this);
	}

	void funC()
	{
		printf("C::funC()的this指標是:%p!\n", this);
	}
};

int main()
{
	cout << sizeof(A) << endl;
	cout << sizeof(B) << endl;
	cout << sizeof(C) << endl;

	C myc;
	myc.funA();
	myc.funB();
	myc.funC();
	return 0;
}

visual studio2017執行結果:

解釋:

(1)A類物件:非靜態成員變數a佔4個位元組,虛擬函式表指標佔4個位元組,共8個位元組

         B類物件:非靜態成員變數b佔4個位元組

         C類繼承自A類和B類:它的非靜態成員變數有 int a; int b; int c;,所以12個位元組()

(2)對於子類物件,它是包含父類物件的,會先為其父類物件成員連續分配記憶體空間,而且分配順序按照其繼承順序進行

如上面的例子中先依次連續分配

父類物件A,B,子類物件C的記憶體空間

(3)對於它的父類物件的this也就指向它本身所在記憶體空間的首地址,而對於子類物件的this它是指向第一個父類物件的首地址,因為整個C物件構成就是它的父類物件+它本身物件,因為(2)中的父類優先連續分配,所以整個子類物件C的首地址也就是父類物件A的記憶體空間的首地址

所以上面的例子中父類物件A和B的this指標都指向它們各自的記憶體空間,而子類物件C的this指標指向A的記憶體空間首地址

圖示理解:

 修改程式碼如下:讓C類重寫父類B中的funB()函式

#include <iostream>
using namespace std;

class A {
public:
	int a;
	A()
	{
		printf("A::A()的this指標是:%p!\n",this);
	}

	void funA()
	{
		printf("A::funA()的this指標是:%p!\n",this);
	}
	virtual void fun()
	{
	
	}
};

class B
{
public:
	int b;
	B()
	{
		printf("B::B()的this指標是:%p!\n", this);
	}

	void funB()
	{
		printf("B::funB()的this指標是:%p!\n", this);
	}
};

class C: public A,public B     //注意繼承順序,決定了後面的記憶體佈局
{
public:
	int c;
	C()
	{
		printf("C::C()的this指標是:%p!\n", this);
	}

	void funC()
	{
		printf("C::funC()的this指標是:%p!\n", this);
	}
	void funB()
	{
		printf("C::funB()的this指標是:%p!\n", this);
	}
};

int main()
{
	cout << sizeof(A) << endl;
	cout << sizeof(B) << endl;
	cout << sizeof(C) << endl;

	C myc;
	myc.funA();
	myc.funB();
        myc.B::funB();
	myc.funC();
	return 0;
}

結果:

解釋:

你呼叫哪個子類的成員函式,這個this指標就會被編譯器自動調整到物件記憶體佈局中 對應該子類物件的起始地址那去;

這裡由於在C類中重寫了funB(),所以myc.funB()會呼叫C中的funB,所以此時this指向C物件的起始地址

而在呼叫myc.B::funB()時,呼叫的是B中的funB,所以此時this指向B物件的起始地址