在c++程式中,去定義一個類物件時,系統會為每一個物件分配儲存空間。
因此,按理說,在一個既有資料又有成員函式時,用同一個類定義多個物件時分配記憶體應該是下面這種情況:
然而很明顯這種方法,有一個重大缺陷:當物件定義比較多時,將在儲存每一個物件中均出現數據和成員函式,而這些成員函式除了僅僅執行的物件不同,其餘程式碼內容完全相同,一個相同的程式碼在每個物件中都儲存,計算機中的資源寸土寸金,這樣造成的記憶體資源大量浪費是很不必要的。
因此在c++中,採取的方法是:物件在儲存時僅僅儲存的為它的資料部分,而他的函式部分儲存的是另一塊儲存空間;一個物件所佔的空間大小隻取決於該物件中資料成員所佔的空間,而與成員函式無關。在呼叫各物件的函式時,都會去呼叫這個公共的函式,從而大大節約儲存空間。即下圖方式:
但是,這樣儲存固然有很大優勢,但是,又有了一個新的問題:即物件使用時,當相同的成員函式引用不同的資料成員時,怎樣能保證引用的是所指向的物件的資料成員呢?
c++中解決這個問題,在每個成員函式中都包含一個特殊的指標,這個指標的名字是固定的,即this指標,每個類都會有一個,它是指向本類物件的指標,它的值是當前被呼叫的成員函式所在物件的起始地址。
舉一個例子進行說明:
程式:
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>#include <string> using namespace std;class Student{private: char _name[20]; char _sex[5]; int _age;public: void InitStudent(char* name, char* sex, int age)//初始化函式 { strcpy(_name, name); strcpy(_sex, sex); _age = age; } void PrintStudent() //列印函式 { cout << _name << " " << _sex << " " << _age << endl; }};int main(){ Student s1,s2,s3; s1.InitStudent("小明","男",18); s1.PrintStudent(); s2.InitStudent("張三", "女", 17); s2.PrintStudent(); s3.InitStudent("李四", "男", 20); s3.PrintStudent(); system("pause"); return 0;}
除錯程式:
1.當程式執行建立物件s1時,開啟監視我們取s1地址,然後除錯程式進入對物件s1進行操作的成員函式,在監視中同樣取this指標的地址
利用同樣的方法對物件s2的地址和對s2資料成員進行操作的成員函式中取this的地址
同樣s3也相同。
透過對比可以很清晰地看到此時this指標所存的地址就是第一個物件的地址,我們都知道在程式編譯的時候編譯器會重新對程式碼進行重寫,在重寫的時候,編譯器將會在類的成員函式引數中新增this指標引數。
比如:上邊函式
void InitStudent(char* name, char* sex, int age)//初始化函式{ strcpy(_name, name); strcpy(_sex, sex); _age = age;} strcpy(_name, name); strcpy(_sex, sex); _age = age;}
在編譯器看來,函式將如下形式:
void InitStudent(Student* const this ,char* name, char* sex, int age)//初始化函式{ strcpy(this->_name, name); strcpy(this->_sex, sex); this->_age = age;}
用this指標將物件的起始地址傳給成員函式,進而進行操作。
在vs編譯器下開啟反彙編也可看到函式進行對物件進行操作時,this指標的變化。。
即this指標先將物件的起始位置傳給成員函式,這樣成員函式引用資料成員時,就會按照this指標的指向找到物件的資料進行操作。
需要注意的是:this指標的型別是*const形;
this指標是類的成員函式獨有的,一般函式無this指標;
this指標的生命週期和成員函式的引數的生命週期相同;
this指標是隱式使用的,它作為引數被編譯器自動傳遞給成員函式;