C++ this指標詳解

2020-07-16 10:04:41
預設情況下,編譯器為類的每個成員函數提供了一個隱式形參,該形參指向被呼叫的成員函數所在的物件。該隱式形參稱為 this

先來看一個 Example 類的程式碼:
class Example
{
    int x;
    public:
        Example(int a){ x = a;}
        void setValue(int);
        int getValue();
}
再來看其成員函數的程式碼:
int Example::getValue()
{
    return x;
}
該成員函數的作用只是返回類物件中的值。以下就是 getValue 函數在程式中可能被呼叫的範例:
int main()
{
    Example ob1 (10), ob2 (20);
    cout << ob1.getValue() << " " << ob2.getValue();
    return 0;
}
在該範例中,程式將列印輸出值 10 20

前面講過,結構或類的不同物件稱為該類的範例,並且類的每個範例都有自己的類資料成員副本。這些資料成員稱為範例成員,因為它們屬於類的範例。它們在不同的物件中可以具有不同的值。因此,在前面的範例中,ob1 物件中的範例成員 x 的值為 10,而 ob2 中的 x 的值為 20。

現在再來看一下該成員函數的程式碼:
int Example::getValue()
{
    return x;
}
該函數應該返回 Example 類的某個物件的 x 成員,但是它如何知道要使用哪個物件呢?這裡會發生的情況就是:預設情況下,編譯器為每個類的每個成員函數提供了一個隱式形參,該形參是指向類物件的指標。因此,如上例所示,getValue 函數配備了一個形參型別的指向 Example 的指標。

同樣地,來看以下成員函數:
void Example::setValue(int a)
{
    x = a;
}
雖然程式設計師在編寫時只釆用了一個 int 型別的形參,但實際上它有兩個形參,其中一個就是指向 Example 類的物件的指標,另外一個自然是由程式設計師指定的以下形參:

int a

在所有這些情況下,隱式物件形參的實際形參就是呼叫成員函數的物件的地址。因此在以下呼叫中:

ob1.getValue()

傳遞給 getValue 函數的隱式形參是 ob1 的地址,而在以下呼叫中:

ob2.setValue(78)

傳遞給 setValue 的隱式形參是 &ob2。

編譯器傳遞給成員函數的隱式指標可以由該函數內的程式碼通過使用保留關鍵字 this 來存取。因此,在以上範例中,Example 類的成員函數也可以通過使用以下表示式來存取呼叫它的物件:

*this

此外,也可以通過同一個指標存取該物件的任何成員。下面的程式說明了這些概念。它修改了 Example 類以包含一個成員函數,它使用 this 指標來列印呼叫它的物件的地址,以及在同一個物件中的範例成員 x 的值。
//ThisExample.h 的內容
class Example
{
    int x;
    public:
        Example(int a){ x = a; }
        void setValue(int);
        void printAddressAndValue();
};

//ThisExample.cpp 的內容
#include "ThisExample.h
#include <iostream>
using namespace std;
void Example::setValue(int a)
{
    x = a;
}
void Example::printAddressAndValue()
{
    cout << "The object at address " << this << " has " << "value " << (*this).x << endl;
}

//main程式的內容
//This program illustrates the this pointer.
#include <iostream>
#include "ThisExample.h"
using namespace std;

int main()
{
    Example ob1 (10), ob2 (20);
    // Print the addresses of the two objects
    cout << "Addresses of objects are " << &ob1 << " and " << &ob2 << endl;
    // Print the addresses and values from within the member function
    ob1.printAddressAndValue();
    ob2.printAddressAndValue();
    return 0;
}
輸出結果為:

Addresses of objects are 0x241ff5c and 0x2411ff58
The object at address 0x241ff5c has value 10
The object at address 0x2411ff58 has value 20

現在來看一看以下成員函數,它是 this 指標的常見用法範例:
void Example::setValue(int a)
{
    x = a;
}
可以看到,該函數很自然地命名了一個形參 a,用來設定成員 x 的值。其實這個形參 a 可以改成一個更加直白的識別符號,使它和成員 x 的意思連線更明顯,例如,可以使用 xValue 之類的,甚至可以使用 x 本身。

但是,一個成員函數的形參如果與類的成員具有相同的識別符號,則會導致類成員被隱藏,使得它在函數內部不可存取。因此,可以使用 this 指標來限定類成員的名字,以使其再次可見。以下就是按這種方式重寫的 setValue 成員函數:
void Example::setValue(int x)
{
    this->x = x;
}

前面講過,this->x 等價於 (*this).x。