| 特性 | 前置遞增 (++x) | 後置遞增 (x++) |
| 運算順序 | 先修改,後回傳 | 先回傳原值,後修改 |
| 回傳型別 | T&(參考) | T(值) |
| 可作左值 | 是 | 否 |
| 實作需求 | 直接修改回傳 *this | 需建立暫時副本 |
| 效能 | 較佳(無副本) | 稍差(含複製建構) |
多載語法區分技巧
**後置版本在參數列加上 int 虛參數**(僅作標記,無實際用途):
// 類別成員函數版本
class Test {
public:
Test& operator++(); // 前置
Test operator++(int); // 後置(int 為區分標記)
};
// 非成員函數版本
Test& operator++(Test&); // 前置
Test operator++(Test&, int); // 後置
完整實作範例(成員函數版)
#include
using namespace std;
class Test {
public:
Test(int a = 0) : a_(a) {}
// 前置遞增:回傳參考
Test& operator++() {
++a_;
return *this;
}
// 後置遞增:回傳值(暫時物件)
Test operator++(int) {
Test Temp(*this); // 複製建構:保存原值
++a_; // 修改自身
return Temp; // 回傳原值副本
}
int GetValue() const { return a_; }
private:
int a_;
};
int main() {
Test a(100);
// 前置遞增鏈式呼叫
++(++a);
cout << "After ++(++a): " << a.GetValue() << endl; // 102
// 觀察後置遞增回傳值
cout << "Post-increment returns: " << (a++).GetValue() << endl; // 102(原值)
cout << "After a++: " << a.GetValue() << endl; // 103
// 後置遞增結果不可再遞增
// (a++)++; // 編譯錯誤
a++; // 正常單獨使用
cout << "After a++: " << a.GetValue() << endl; // 104
return 0;
}
非成員函數版本實作
class Test {
friend Test& operator++(Test&); // 前置
friend Test operator++(Test&, int); // 後置
public:
Test(int a = 0) : a_(a) {}
int GetValue() const { return a_; }
private:
int a_;
};
Test& operator++(Test& obj) { // 前置
++obj.a_;
return obj;
}
Test operator++(Test& obj, int) { // 後置
Test Temp(obj); // 複製建構
++obj.a_;
return Temp;
}
延伸至其他單目運算子
同樣規則適用於:--、*(解參考)、&(取址)、+/-(一元正負)等單目運算子的前後置/前後綴區分。
最佳實踐建議
- 優先提供前置版本:效能較好,回傳參考支援鏈式操作
- 後置版本按需提供:確有語意需求(如迭代器
it++)才實作
- 回傳型別嚴格區分:前置
T&,後置 T
- 後置實作呼叫前置:避免重複邏輯
Test Test::operator++(int) {
Test Temp(*this);
++(*this); // 復用前置邏輯
return Temp;
}
- 迭代器模式:STL 迭代器同時提供兩者,
++it 優於 it++
常見錯誤與陷阱
| 錯誤 | 後果 | 修正 |
| 前置回傳值而非參考 | 無法鏈式呼叫、效能損失 | 回傳 T& |
| 後置回傳參考 | 回傳區域暫時物件參考 → 未定義行為 | 回傳 T(值) |
| 忘記複製建構 | 修改後值被回傳,語意錯誤 | 建立 Temp(*this) |
虛參數 int 漏寫 | 無法區分前後置,重載衝突 | 後置必須加 int |
- 上一篇文章: C++ RAII 技巧:自動化臨時記憶體與等待游標的資源管理
- 下一篇文章: C/C++ 利用空指標哨兵簡化陣列遍歷:消除迴圈計數器與邊界檢查
Copyright ©
程式碼之家 All Rights Reserved