名稱空間
變體
操作

遞增/遞減運算子

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 

遞增/遞減運算子用於增加或減少物件的值。

運算子名稱 語法 可過載 原型示例(對於 class T
類定義內部 類定義外部
前置遞增 ++a T& T::operator++(); T& operator++(T& a);
前置遞減 --a T& T::operator--(); T& operator--(T& a);
後置遞增 a++ T T::operator++(int); T operator++(T& a, int);
後置遞減 a-- T T::operator--(int); T operator--(T& a, int);
注意
  • 內建運算子的字首版本返回*引用*,而後綴版本返回*值*,典型的使用者定義過載也遵循此模式,以便使用者定義的運算子可以像內建運算子一樣使用。然而,在使用者定義的運算子過載中,任何型別都可以用作返回型別(包括void)。
  • int 引數是一個虛擬引數,用於區分運算子的字首和字尾版本。當呼叫使用者定義的字尾運算子時,該引數中傳遞的值始終為零,儘管可以透過使用函式呼叫表示法(例如,a.operator++(2)operator++(a, 2))呼叫運算子來更改它。

目錄

[編輯] 字首運算子

字首遞增和遞減表示式的形式為

++ 表示式
-- 表示式
1) 字首遞增 (pre-increment)
2) 字首遞減 (pre-decrement)

[編輯] 內建字首運算子

1) 表示式 ++x 等價於 x += 1,但有以下例外情況
  • 如果 表示式 的型別是 (可能帶有 volatile 限定的) bool,則將 表示式 設定為 true。這種遞增已被棄用。
(C++17 前)
  • 如果 表示式 的型別是 (可能帶有 cv 限定的) bool,則程式格式錯誤。
(C++17 起)
  • 如果 表示式 的型別是 volatile 限定的,則遞增已被棄用。
(C++20 起)
2) 表示式 --x 等價於 x -= 1,但有以下例外情況
  • 如果 表示式 的型別是 (可能帶有 cv 限定的) bool,則程式格式錯誤。
  • 如果 表示式 的型別是 volatile 限定的,則遞減已被棄用。
(C++20 起)

[編輯] 過載

在針對使用者定義運算子的過載決議中,對於除 bool 之外的每個可選 volatile 限定的算術型別 A,以及每個可選 cv 限定的物件型別的可選 volatile 限定指標 P,以下函式簽名參與過載決議

A& operator++(A&)
bool& operator++(bool&)
(已棄用)(直到 C++17)
P& operator++(P&)
A& operator--(A&)
P& operator--(P&)

[編輯] 字尾運算子

字尾遞增和遞減表示式的形式為

表示式 ++
表示式 --
1) 字尾遞增 (post-increment)
2) 字尾遞減 (post-decrement)

[編輯] 內建字尾運算子

字尾遞增或遞減的結果是透過對 表示式 應用左值到右值轉換(在修改之前)獲得的值。結果的型別是 表示式 型別的 cv-unqualified 版本。

如果 表示式 不是算術型別(除可能 cv 限定的 bool 之外)(C++17 起) 的可修改左值,也不是指向完整物件型別的指標,則程式格式錯誤。

如果 表示式 的型別是 volatile 限定的,則遞增或遞減已被棄用。

(C++20 起)
1) 表示式 的值被修改,如同它是字首 ++ 運算子的運算元一樣。
2) 表示式 的值被修改,如同它是字首 -- 運算子的運算元一樣。

字尾遞增或遞減的值計算在 表示式 的修改之前排序。相對於不確定排序的函式呼叫,字尾遞增或遞減的操作是單個求值。

[編輯] 過載

在針對使用者定義運算子的過載決議中,對於除 bool 之外的每個可選 volatile 限定的算術型別 A,以及每個可選 cv 限定的物件型別的可選 volatile 限定指標 P,以下函式簽名參與過載決議

A operator++(A&, int)
bool operator++(bool&, int)
(已棄用)(直到 C++17)
P operator++(P&, int)
A operator--(A&, int)
P operator--(P&, int)

[編輯] 示例

#include <iostream>
 
int main()
{
    int n1 = 1;
    int n2 = ++n1;
    int n3 = ++ ++n1;
    int n4 = n1++;
//  int n5 = n1++ ++;   // error
//  int n6 = n1 + ++n1; // undefined behavior
    std::cout << "n1 = " << n1 << '\n'
              << "n2 = " << n2 << '\n'
              << "n3 = " << n3 << '\n'
              << "n4 = " << n4 << '\n';
}

輸出

n1 = 5
n2 = 2
n3 = 4
n4 = 4

[編輯] 注意

由於涉及副作用,內建遞增和遞減運算子必須小心使用,以避免由於違反排序規則而導致未定義行為。

由於在後置遞增和後置遞減期間會構造物件的臨時副本,因此在不使用返回值的上下文中,前置遞增或前置遞減運算子通常更高效。

[編輯] 標準庫

遞增和遞減運算子為許多標準庫型別過載。特別是,每個LegacyIterator都過載了 operator++,每個LegacyBidirectionalIterator都過載了 operator--,即使這些運算子對於特定的迭代器是空操作。

算術型別的過載
將原子值遞增或遞減一
(std::atomic<T> 的 public 成員函式) [編輯]
增加或減少刻度計數
(std::chrono::duration<Rep,Period> 的 public 成員函式) [編輯]
迭代器型別的過載
前進迭代器
(std::raw_storage_iterator<OutputIt,T> 的 public 成員函式) [編輯]
遞增或遞減 reverse_iterator
(std::reverse_iterator<Iter> 的 public 成員函式) [編輯]
遞增或遞減 move_iterator
(std::move_iterator<Iter> 的 public 成員函式) [編輯]
無操作
(std::front_insert_iterator<Container> 的 public 成員函式) [編輯]
無操作
(std::back_insert_iterator<Container> 的 public 成員函式) [編輯]
無操作
(std::insert_iterator<Container> 的 public 成員函式) [編輯]
前進迭代器
(std::istream_iterator<T,CharT,Traits,Distance> 的 public 成員函式) [編輯]
無操作
(std::ostream_iterator<T,CharT,Traits> 的 public 成員函式) [編輯]
前進迭代器
(std::istreambuf_iterator<CharT,Traits> 的 public 成員函式) [編輯]
無操作
(std::ostreambuf_iterator<CharT,Traits> 的 public 成員函式) [編輯]
將迭代器推進到下一個匹配項
(std::regex_iterator<BidirIt,CharT,Traits> 的 public 成員函式) [編輯]
將迭代器推進到下一個子匹配項
(std::regex_token_iterator<BidirIt,CharT,Traits> 的 public 成員函式) [編輯]

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 2855 C++98 通常的算術轉換應用於內建前置遞增和
前置遞減,但未應用於其後綴對應項[1]
也已應用
CWG 2901 C++98 左值到右值轉換未應用於
內建字尾遞增和字尾遞減
已應用
  1. 字首 ++x 等價於 x += 1,後者適用於通常的算術轉換(即在 decltype(x)int 之間產生一個共同型別)。然而,字尾 x++ 的效果僅僅是“給 x 加一”,不存在二元運算子,因此不會發生通常的算術轉換。

[編輯] 參見

運算子優先順序

運算子過載

常見運算子
賦值 遞增
遞減
算術 邏輯 比較 成員
訪問
其他

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[...]
*a
&a
a->b
a.b
a->*b
a.*b

函式呼叫

a(...)
逗號

a, b
條件運算子

a ? b : c
特殊運算子

static_cast 將一種型別轉換為另一種相關型別
dynamic_cast 在繼承層次結構內進行轉換
const_cast 新增或移除 cv-限定符
reinterpret_cast 將型別轉換為不相關型別
C 風格的轉換 透過 static_castconst_castreinterpret_cast 的組合將一種型別轉換為另一種型別
new 建立具有動態儲存期的物件
delete 銷燬先前由 new 表示式建立的物件並釋放獲得的記憶體區域
sizeof 查詢型別的大小
sizeof... 查詢 的大小 (C++11 起)
typeid 查詢型別的型別資訊
noexcept 檢查表示式是否可以丟擲異常 (C++11 起)
alignof 查詢型別的對齊要求 (C++11 起)

C 文件 用於 遞增/遞減運算子