基本介紹
- 中文名:C++ this 指針
- 外文名:C++ this pointer
- 作用:編譯器自動將參數傳遞給函式
- 套用 :this指針只能在一類函式中調用
- 使用:this指針是自動生成,且自動隱藏
- 解析:不同對象調用同一個函式代碼段
主要作用,如何使用,使用示例,詳細解析,套用參考,
主要作用
一個對象的this指針並不是對象本身的一部分,不會影響sizeof(對象)的結果。this作用域是在類內部,當在類的非靜態成員函式中訪問類的非靜態成員的時候,編譯器會自動將對象本身的地址作為一個隱含參數傳遞給函式。也就是說,即使你沒有寫上this指針,編譯器在編譯的時候也是加上this的,它作為非靜態成員函式的隱含形參,對各成員的訪問均通過this進行。
例如,調用date.SetMonth(9) <===> SetMonth(&date, 9),this幫助完成了這一轉換 .
如何使用
一種情況就是,在類的非靜態成員函式中返回類對象本身的時候,直接使用 return *this;另外一種情況是當參數與成員變數名相同時使用this指針,如this->n = n (不能寫成n = n)。
使用示例
根據以下程式來說明this指針
#include<iostream>using namespace std;class Point{ private: int x,y; public: Point(int a,int b) { x=a; y=b; } void MovePoint(int a,int b) { x+=a; y+=b; } void print() { cout<<"x="<<x<<"y="<<y<<endl; } };int main(){ Point point1(10,10); point1.MovePoint(2,2); point1.print(); return 0;}
當對象point1調用MovePoint(2,2)函式時,即將point1對象的地址傳遞給了this指針。
MovePoint函式的原型應該是 void MovePoint( Point *this, int a, int b);第一個參數是指向該類對象的一個指針,我們在定義成員函式時沒看見是因為這個參數在類中是隱含的。這樣point1的地址傳遞給了this,所以在MovePoint函式中便顯式的寫成:
void MovePoint(int a, int b) { this->x +=a; this-> y+= b;}
即可以知道,point1調用該函式後,也就是point1的數據成員被調用並更新了值。
4. 關於this指針的一個經典回答:
當你進入一個房子後,
你可以看見桌子、椅子、地板等,
但是房子你是看不到全貌了。
對於一個類的實例來說,
你可以看到它的成員函式、成員變數,
但是實例本身呢?
this是一個指針,它時時刻刻指向你這個實例本身
5.使用this指針要注意的事項
相信大家對指針的用法已經很熟了,這裡也不多說些定義性的東西了,只說一下指針使用中的注意事項吧。
一.在定義指針的時候注意連續聲明多個指針時容易犯的錯誤,例如int * a,b;這種聲明是聲明了一個指向int類型變數的指針a和一個int型的變數b,這時候要清醒的記著,而不要混淆成是聲明了兩個int型指針。
二.要避免使用未初始化的指針。很多運行時錯誤都是由未初始化的指針導致的,而且這種錯誤又不能被編譯器檢查所以很難被發現。這時的解決辦法就是儘量在使用指針的時候定義它,如果早定義的話一定要記得初始化,當然初始化時可以直接使用cstdlib中定義的NULL也可以直接賦值為0,這是很好的編程習慣。
三.指針賦值時一定要保證類型匹配,由於指針類型確定指針所指向對象的類型,因此初始化或賦值時必須保證類型匹配,這樣才能在指針上執行相應的操作。
詳細解析
在前面曾經提到過: 每個對象中的數據成員都分別占有存儲空間,如果對同一個類定義了n個對象,則有n組同樣大小的空間以存放n個對象中的數據成員。但是,不同對象都調用同一個函式代碼段。
那么,當不同對象的成員函式引用數據成員時,怎么能保證引用的是所指定的對象的數據成員呢?假如,對於例9.6程式中定義的Box類,定義了3個同類對象a,b,c。
如果有a.volume( ) ,應該是引用對象a中的height,width和length,計算出長方體a的體積。
如果有b.volume( ) ,應該是引用對象b中的height,width和length,計算出長方體b的體積。
而現今都用同一個函式段,系統怎樣使它分別引用a或b中的數據成員呢?在每一個成員函式中都包含一個特殊的指針,這個指針的名字是固定的,稱為this指針。它是指向本類對象的指針,它的值是當前被調用的成員函式所在的對象的起始地址。
例如,當調用成員函式a.volume時,編譯系統就把對象a的起始地址賦給this指針,於是在成員函式引用數據成員時,就按照this的指向找到對象a的數據成員。例如volume函式要計算height*width*length的值,實際上是執行:
(this->height)*(this->width)*(this->length)
由於當前this指向a,因此相當於執行:
(a.height)*(a.width)*( a.length)
這就計算出長方體a的體積。
同樣如果有b.volume( ) ,編譯系統就把對象b的起始地址賦給成員函式volume的this指針,顯然計算出來的是長方體b的體積。this指針是隱式使用的,它是作為參數被傳遞給成員函式的。
本來,成員函式volume的定義如下:
int Box::volume( )
{
return (height*width*length);
}
C++把它處理為
int Box::volume(Box *this)
{
return (this->height * this->width * this->length);
}
即在成員函式的形參表列中增加一個this指針。
在調用該成員函式時,實際上是用以下方式調用的:
a.volume(&a);
將對象a的地址傳給形參this指針。然後按this的指向去引用其他成員。
需要說明: 這些都是編譯系統自動實現的,編程式者不必人為地在形參中增加this指針,也不必將對象a的地址傳給this指針。在需要時也可以顯式地使用this指針。
例如在Box類的volume函式中,下面兩種表示方法都是合法的、相互等價的。
return (height * width * length); //隱含使用this指針
return (this->height * this->width * this->length); //顯式使用this指針
可以用*this表示被調用的成員函式所在的對象,*this就是this所指向的對象,即當前的對象。
例如在成員函式a.volume( )的函式體中,如果出現*this,它就是本對象a。上面的return語句也可寫成
return((*this).height * (*this).width * (*this).length);
注意*this兩側的括弧不能省略,不能寫成*this.height。
所謂“調用對象a的成員函式f”,實際上是在調用成員函式f時使this指針指向對象a,從而訪問對象a的成員。在使用“調用對象a的成員函式f”時,應當對它的含義有正確的理解。
套用參考
this指針只能在一個類的成員函式中調用,它表示當前對象的地址。下面是一個例子:
voidDate::setMonth(intmn){ month=mn; this->month=mn; (*this).month=mn; //這三句是等價的}
1.this只能在成員函式中使用。
全局函式,靜態函式都不能使用this。
實際上,成員函式默認第一個參數為T*const register this。
如:
class A{public: int func( int p){}};
其中,func的原型在編譯器看來應該是: int func(A*const register this, int p);
2. 由此可見,this在成員函式的開始前構造的,在成員的結束後清除。
這個生命周期同任一個函式的參數是一樣的,沒有任何區別。
當調用一個類的成員函式時,編譯器將類的指針作為函式的this參數傳遞進去。如:
A a;
a.func(10);
此處,編譯器將會編譯成: A::func(&a, 10);
嗯,看起來和靜態函式沒差別,對嗎?不過,區別還是有的。編譯器通常會對this指針做一些最佳化的,因此,this指針的傳遞效率比較高--如vc通常是通過ecx暫存器來傳遞this參數。
3. 回答
#1:this指針是什麼時候創建的?
this在非靜態成員中有意義,作為右值可以直接在編譯時確定其存在,運行時無所謂創建。
#2:this指針存放在何處?堆,棧,全局變數,還是其他?
由上一問可知,this指針無需顯式儲存記憶體中。只要存儲對象的記憶體位置確定,對應的this指針就被確定了。
#3:this指針如何傳遞給類中函式的?綁定?還是在函式參數的首參數就是this指針.那么this指針又是如何找到類實例後函式的?
this是通過函式參數的首參數來傳遞的。this指針是在調用之前生成的。類實例後的函式,沒有這個說法。類在實例化時,只分配類中的變數空間,並沒有為函式分配空間。自從類的函式定義完成後,它就在那兒,不會跑的。
#4:this指針如何訪問類中變數的?
如果不是類,而是結構的話,那么,如何通過結構指針來訪問結構中的變數呢?如果你明白這一點的話,那就很好理解這個問題了。
在C++中,struct是一種類類型,struct和class只有一個區別的:class的成員和繼承默認的訪問控制許可權是private,而struct是public。
this是class或public的對象的指針。
#5:我們只有獲得一個對象後,才能通過對象使用this指針,如果我們知道一個對象this指針的位置可以直接使用嗎?
this指針只有在非靜態成員中才有意義。獲得一個對象後,不需要在類外部使用this對其操作。應當注意this是一個右值(方法的一個隱式參數),不存在所謂的this的“位置”,只是this表示了對象的存儲位置而已。&this違反語義規則,是錯誤的用法,不會編譯通過。
#6:每個類編譯後,是否創建一個類中函式表保存函式指針,以便用來調用函式?
一般來說,對於類成員函式(不論是靜態還是非靜態的成員函式)都不需要創建一個在運行時的函式表來保存。只有虛函式才會被放到函式表中。
但是,即使是虛函式,如果編譯器能明確知道調用的是哪個函式,編譯器就不會通過函式表中的指針來間接調用,而是可以直接調用該函式。