1. 程式人生 > >this指標和 *this

this指標和 *this

        我們都知道,類的成員函式有一個附加的隱形形參,即指向該類物件的this指標,它與呼叫成員函式的物件繫結在一起。那麼,這個this指標究竟是什麼樣的指標呢?其解引用*this返回的又是怎樣的一個物件呢?

首先,我們以《C++ Primer》書中的Screen類為例說明,這個類只是簡單宣告,有些成員函式的具體實現沒有定義。不必關注成員函式的實現,只需要看它的形式即可。



//定義一個名為Screen的型別來表示計算機上的視窗
#include <iostream>
#include <string>
using namespace std;
class Screen
{
public:
	//使用類型別名來簡化類
	typedef string::size_type index;
	//建構函式
	Screen(index hght,index wdth,const string &cntnts=""):
	height(hght),width(wdth),cursor(0),contents(cntnts){}
	//返回游標的位置
	index get_cursor() const{return cursor;};
	//增加三個成員函式,返回*this
	Screen& move(index r,index c);//給定兩個index值,將游標移至新位置
	Screen& set(char);//將特定字元設定為特定值
	const Screen& display(ostream &os) const;//輸出內容
private:
	std::string contents;//視窗內容
	index cursor;//游標當前停留的位置
	index height,width;//視窗的高度和寬度
};
//給定兩個index值,將游標移至新位置
Screen& Screen::move(index r,index c)
{
	index row=r*width;
	cursor=row+c;
	return *this;
}
//將特定字元或游標指向的字元設定為特定值
Screen& Screen::set(char c)
{
	contents[cursor]=c;
	return *this;
}
//輸出內容
const Screen& Screen::display(ostream &os) const
{
	os<<contents;
	return *this;
}
int main()
{
	//根據螢幕的高度、寬度和內容的值來建立Screen
	Screen myscreen(5,6,"abcde\nfghij\nklmno\pqrst\nuvwxy");
	myscreen.move(4,0).set('#').display(cout);
	cout<<endl;
	return 0;
}

基本概念

  1. const指標——指標本身的值不可修改,只能指向指定位置的物件
    其定義如下:
    int errNumb = 0;
    int *const curErr=&errNumb;//curErr是一個指向int型物件的const指標
    可以改變const指標所指向的值,但不能改變const指標所儲存的地址,如下:
    *curErr=1;//curErr所指向的值變為1,即errNumb=1
    ++curErr;//錯誤,curErr是一個常量,不能改變
    const指標在定義時必須初始化,一經初始化,則指標本身不可再修改,只能指向初始化時的物件。
  2. 指向const物件的指標——只能讀取物件,不能利用指標修改物件
    其定義如下:
    const double pi = 3.14;
    const double *cptr = &pi;//cptr是一個指向const物件pi的指標
    *cptr=3.15; //錯誤,不能通過指向常物件的指標修改物件
    ++cptr;//正確,指向常物件的指標可以指向別處
  3. 常(const)成員函式
    在形參表後用const修飾的成員函式,表示只能讀取類的資料成員,不能修改。如上例中的index get_cursor()const{return cursor;};
  4. 常(const)物件
    在定義類物件時用const修飾的物件,常物件只能呼叫類中的常成員函式,而普通的物件則沒有此限制。如下例:
    const Screen herscreen();//herscreen就是一個Screen型別的常物件

this指標

  1. this指標是指向類型別的const指標
    呼叫成員函式時,隱藏的this指標被初始化為呼叫成員函式的物件的地址,可以改變this所指向的值,但不能改變this所儲存的地址,即this指標只能指向該物件,不能指向別的物件。所以,無論在非const成員函式還是const成員函式中,this首先是一個指向類型別的const指標。在上例中,非const函式Screen& move(index r,index c)的this型別如下:
    Screen *const
    this
  2. const成員函式中的this指標——指向常(const)物件的const指標
    在普通的非const成員函式中,this的型別就是一個指向類型別的const指標。
    而在const成員函式中,因為不能通過this指標修改類的資料成員,只能讀資料成員,故this的型別是一個指向常(const)類物件的const指標。既不能改變this所指向的物件,也不能改變this所儲存的地址。在上例中,const成員函式 get_cursor() const的this的型別如下:
    const Screen *const this

返回*this——返回的是一個物件的引用

  1. 何時返回*this
    當我們需要將一個物件作為整體引用而不是引用物件的一個成員是。最常見的情況就是在這樣的函式中返回*this:
    該函式返回對呼叫該函式的物件的引用。
    如上例中的
    myscreen.move(4,0).set('#');
    等價於
    myscreen.move(4,0);
    myscreen.set('#');
  2. 返回的物件引用是什麼型別:常物件引用 or not?
    在普通的非const成員函式中,*this返回的普通的物件引用。在上例中,非const成員函式move( )返回的就是一個普通的物件引用:
    //給定兩個index值,將游標移至新位置
    Screen& Screen::move(index r,index c)
    {
    	index row=r*width;
    	cursor=row+c;
    	return *this;
    }

    而在const成員函式中,*this返回的是常(const)物件引用。在上例中,const成員函式display() const返回的就是一個常(const)物件的引用:
    //輸出內容
    const Screen& Screen::display(ostream &os) const
    {
    	os<<contents;
    	return *this;
    }
    注意:
    不能從const成員函式返回指向類物件的普通引用,而應該是const引用。const成員函式只能返回*this作為一個const引用。

    Screen&
     display(ostream &os) const; //錯誤,const成員函式返回的應該是一個const物件引用
    const Screen& display(ostream &os) const; //正確
    那麼返回型別之間的區別又會導致什麼結果呢?
    我們知道,常(const)物件只能呼叫const成員函式,而普通物件既能呼叫const成員函式,又能呼叫非const成員函式。所以,我們可以判斷以下呼叫是否正確?
    mysceen.move(4,0).set('#'); //正確,因為非const成員函式move()返回的是普通引用,可以呼叫一切成員函式
    myscreen.move(4,0).display(cout);//正確
    myscreen.display(cout).set('#'); //錯誤,因為const成員函式display()返回的常物件引用,只能呼叫const成員函式,而set.()是非const成員函式

    因此,我們可以確定,返回型別的不同對呼叫成員函式有了限制。
現在,我們可以做出結論了:
  1. 非const成員函式的this是一個指向類型別的const指標,可以改變this所指向的值,但不能改變this所儲存的地址,即不能再指向別的物件。
    const成員函式的this是一個指向常(const)類物件的const指標,既不能改變this所指向的物件的值,也不能改變this所儲存的地址。

  2. 非const成員函式的*this返回的是普通引用,可以呼叫一切成員函式。
    const成員函式的*this返回的是常(const)物件引用,只能呼叫const成員函式。
上面只是我學習過程中的一些淺顯理解,拿出來與大家共享,也希望得到大家的指點。