C++ 中 ++a(前綴)與 a++(後綴)雖同為遞增,但語義差異巨大:
int a = 0;
++(++a); // 合法:前綴回傳左值(引用)
(a++)++; // 錯誤:後綴回傳右值(暫時物件),非左值
編譯器報錯「++ 需要左值」,揭示核心差別:前綴回傳引用,後綴回傳值。
| 特性 | 前綴 ++obj | 後綴 obj++ |
|---|---|---|
| 操作順序 | 先遞增,後回傳物件本身(引用) | 先回傳原值(建立暫時物件),後遞增 |
| 回傳類型 | Type&(引用) | Type(值) |
| 效能 | 無額外複製,效率高 | 需建構暫時物件,有複製開銷 |
| 可作左值 | 是 | 否 |
C++ 規定:後綴版本多一個 int 佔位參數(無實際用途,僅供編譯器區分)。
// 友元函式寫法
class Test {
friend Test& operator++(Test&); // 前綴
friend Test operator++(Test&, int); // 後綴(int 佔位)
int a;
};
Test& operator++(Test& t) { // 前綴
++t.a;
return t; // 回傳引用
}
Test operator++(Test& t, int) { // 後綴
Test temp(t); // 複製原值
++t.a; // 遞增本體
return temp; // 回傳暫時物件(值)
}
class Test {
int a;
public:
Test& operator++() { // 前綴:無參數
++a; return *this;
}
Test operator++(int) { // 後綴:int 佔位
Test temp(*this);
++a;
return temp;
}
};
int main() {
Test a(100);
++(++a); // 連續前綴,合法
cout << a.a << endl; // 102
cout << (a++).a << endl; // 印出 102(舊值),a 變 103
cout << a.a << endl; // 103
(a++)++; // 錯誤:後綴回傳值不可再遞增
// 若強行編譯通過(某舊編譯器),a 僅增 1 變 104,非 105
}
++it 避免暫時物件建構,效能更優。arr[i++] = val。前綴/後綴遞增的差異源於 C++ 對運算符語義的嚴格定義。重載時務必遵循「前綴回傳引用、後綴回傳值」及「後綴加 int 佔位」慣例,才能讓自訂類型行為與內建型別一致,避免難以診斷的邏輯錯誤。