命名空间
变体
操作

递增/递减运算符

来自 cppreference.cn
< 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 文档 用于 递增/递减运算符