递增/递减运算符
递增/递减运算符用于增加或减少对象的值。
| 运算符名称 | 语法 | 可重载 | 原型示例(对于 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); |
| ||||
目录 |
[编辑] 前缀运算符
前缀递增和递减表达式的形式为
++ 表达式 |
|||||||||
-- 表达式 |
|||||||||
[编辑] 内置前缀运算符
|
(C++17 前) |
|
(C++17 起) |
|
(C++20 起) |
- 如果 表达式 的类型是 (可能带有 cv 限定的) bool,则程序格式错误。
|
(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&) |
||
[编辑] 后缀运算符
后缀递增和递减表达式的形式为
表达式 ++ |
|||||||||
表达式 -- |
|||||||||
[编辑] 内置后缀运算符
后缀递增或递减的结果是通过对 表达式 应用左值到右值转换(在修改之前)获得的值。结果的类型是 表达式 类型的 cv-unqualified 版本。
如果 表达式 不是算术类型(除可能 cv 限定的 bool 之外)(C++17 起) 的可修改左值,也不是指向完整对象类型的指针,则程序格式错误。
|
如果 表达式 的类型是 volatile 限定的,则递增或递减已被弃用。 |
(C++20 起) |
++ 运算符的操作数一样。-- 运算符的操作数一样。后缀递增或递减的值计算在 表达式 的修改之前排序。相对于不确定排序的函数调用,后缀递增或递减的操作是单个求值。
[编辑] 重载
在针对用户定义运算符的重载决议中,对于除 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 | 左值到右值转换未应用于 内置后缀递增和后缀递减 |
已应用 |
- ↑ 前缀 ++x 等价于 x += 1,后者适用于通常的算术转换(即在 decltype(x) 和 int 之间产生一个共同类型)。然而,后缀 x++ 的效果仅仅是“给 x 加一”,不存在二元运算符,因此不会发生通常的算术转换。
[编辑] 参见
| 常见运算符 | ||||||
|---|---|---|---|---|---|---|
| 赋值 | 递增 递减 |
算术 | 逻辑 | 比较 | 成员 访问 |
其他 |
|
a = b |
++a |
+a |
!a |
a == b |
a[...] |
函数调用 a(...) |
| 逗号 a, b | ||||||
| 条件运算符 a ? b : c | ||||||
| 特殊运算符 | ||||||
|
static_cast 将一种类型转换为另一种相关类型 | ||||||
| C 文档 用于 递增/递减运算符
|