命名空间
变体
操作

递增/递减运算符

来自 cppreference.com
< cpp‎ | 语言
 
 
C++ 语言
 
 

递增/递减运算符会递增或递减对象的 value。

运算符名称 语法 可重载 原型示例(对于 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) 前缀增量(预增量)
2) 前缀减量(预减量)

[编辑] 内置前缀运算符

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) 后缀增量(后增量)
2) 后缀减量(后减量)

[编辑] 内置后缀运算符

后缀增量或减量的结果是 表达式 在修改之前的 prvalue 复制。结果的类型是 表达式 类型的不带 cv 限定符的版本。

如果 表达式 不是算术类型的可修改左值,除了(可能是具有 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--,即使这些运算符对于特定迭代器是无操作的。

算术类型的重载
将原子值增量或减量 1
(std::atomic<T> 的公共成员函数) [编辑]
将滴答计数增量或减量
(std::chrono::duration<Rep,Period> 的公共成员函数) [编辑]
迭代器类型的重载
使迭代器前进
(std::raw_storage_iterator<OutputIt,T> 的公共成员函数) [编辑]
使迭代器前进或后退
(std::reverse_iterator<Iter> 的公共成员函数) [编辑]
使迭代器前进或后退
(std::move_iterator<Iter> 的公共成员函数) [编辑]
无操作
(std::front_insert_iterator<Container> 的公共成员函数) [编辑]
无操作
(std::back_insert_iterator<Container> 的公共成员函数) [编辑]
无操作
(std::insert_iterator<Container> 的公共成员函数) [编辑]
使迭代器前进
(std::istream_iterator<T,CharT,Traits,Distance> 的公共成员函数) [编辑]
无操作
(std::ostream_iterator<T,CharT,Traits> 的公共成员函数) [编辑]
使迭代器前进
(std::istreambuf_iterator<CharT,Traits> 的公共成员函数) [编辑]
无操作
(std::ostreambuf_iterator<CharT,Traits> 的公共成员函数) [编辑]
使迭代器前进到下一个匹配项
(std::regex_iterator<BidirIt,CharT,Traits> 的公共成员函数) [编辑]
使迭代器前进到下一个子匹配项
(std::regex_token_iterator<BidirIt,CharT,Traits> 的公有成员函数) [编辑]

[编辑] 错误报告

以下行为变更错误报告被追溯应用于先前发布的 C++ 标准。

DR 应用于 已发布的行为 正确行为
CWG 2855 C++98 对前置递增和
前置递减应用了通常的算术转换,但没有应用于其后置对应项[1]
也应用
  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 文档 针对 递增/递减运算符