【C++ 筆記】this pointer - part 21

很感謝你點進來這篇文章。

你好,我並不是什麼 C++、程式語言的專家,所以本文若有些錯誤麻煩請各位鞭大力一點,我極需各位的指正及指導!!本系列文章的性質主要以詼諧的口吻,一派輕鬆的態度自學程式語言,如果你喜歡,麻煩留言說聲文章讚讚吧!

this 指針(this pointer)

在 C++ OOP 中,每當呼叫非靜態成員函數時,編譯器會傳遞一種特殊的指標,稱為 “this” 指標。

它特殊的點就在於:它是隱形的。也就是說我們平常在設計 class 的時候,並不會看見 this pointer。

:::success
this pointer 指向當前呼叫該函數的物件實例,讓程式可以在成員函數內部存取該物件的成員變數與其他成員函式。
:::

:::success
在 C++ 中,每個物件都能透過 this 指標來存取自己的位址。
:::

:::info
Friend Function 沒有 this pointer,因為 Friend 不是類的成員,只有成員函數才有 this 指針。
:::

this pointer 是拿來幹嘛的?


具以下三種用途:

  1. 辨識當前的物件

this pointer 代表正在執行函數的物件本身,使得在函數內部能明確區分物件成員與區域變數或參數。

如:在成員函數中若參數名稱與成員變數相同,利用 this-> 可避免命名衝突。

  1. 鏈式呼叫(OOP的一個專有名詞)

在運算子重載或方法設計中,常需回傳物件本身以實現鏈式運算(chaining)。透過 return *this;,可以讓呼叫者連續呼叫多個成員函式。

鏈式呼叫相關資訊:https://zh.wikipedia.org/zh-tw/%E6%96%B9%E6%B3%95%E9%93%BE%E5%BC%8F%E8%B0%83%E7%94%A8

  1. 防止自我指定

在指定運算子等運算中,this pointer 可檢查是否為自我賦值(指定),避免不必要的運算跟潛在錯誤。

為了要理解 this pointer,我們必須要知道…


  • 每個物件都有自己的資料成員副本。

每個物件都有自己的資料成員副本,所有物件共享一份成員函數的副本。

那麼現在的問題是,如果每個成員函數只有一份副本,並被多個物件使用,則如何正確存取和更新資料成員?

這就需要依靠 this pointer 的機制了。

  • this pointer 在靜態成員函數中不可用,因為靜態成員函數可以不使用任何物件(用類名)來呼叫。

this pointer 的使用說明書


在每個非靜態成員函數中,this pointer 都是隱式存在的,其型態依照函數是否為常數成員而有所不同:

  • 非 const 成員函數:型態為 ClassName*
  • const 成員函數:型態為 const ClassName*

使用 this pointer 時,可透過 this-> 存取物件的成員,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyClass {
public:
int value;

MyClass(int value) : value(value) {}

// 使用 this pointer 避免參數與成員名稱衝突
void setValue(int value) {
this->value = value;
}

// 回傳物件本身以支援鏈式呼叫
MyClass& increment() {
++(this->value);
return *this;
}
};

  • setValue 函數使用 this->value 來明確指定要修改的是物件的成員變數,而非函式參數。
  • increment 函數透過回傳 *this,使得可進行連續的呼叫,如 obj.increment().increment();

範例:運算子重載(鏈式呼叫)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;

class Counter {
private:
int count;
public:
Counter(int c = 0) : count(c) {}

// 賦值運算子重載:利用 this 檢查自我賦值,並回傳物件本身以支援鏈式賦值
Counter& operator=(const Counter& other) {
if (this != &other) { // 防止自我賦值
this->count = other.count;
}
return *this;
}

// 增加計數,並回傳物件本身
Counter& increment() {
++(this->count);
return *this;
}

// 顯示目前計數
void display() const {
cout << "Count: " << count << endl;
}
};

int main() {
Counter a(5), b;
b = a;
b.increment().increment(); // 鏈式呼叫:連續增加兩次
a.display(); // 輸出:Count: 5
b.display(); // 輸出:Count: 7
return 0;
}
  • 第 31 行,用到了 this pointer 來比較物件位址,避免將自己賦值給自己(自我賦值)。
  • increment 函數使用 ++(this->count) 增加計數,並回傳 *this 使得可以連續呼叫。
  • 第 33 行,使用鏈式呼叫,將物件 b 的計數從 5 增加到 7。

參考資料

‘this’ pointer in C++ - GeeksforGeeks

C++ 中的 this 指针 | 菜鸟教程

[C++] this 指標 – 科技讀蟲

this指標 | Microsoft Learn