赋值运算符修改对象的值。

运算符名 语法 可重载 原型示例(对于 class T)
类内定义 类外定义
简单赋值 a = b T& T::operator =(const T2& b); N/A
加法赋值 a += b T& T::operator +=(const T2& b); T& operator +=(T& a, const T2& b);
减法赋值 a -= b T& T::operator -=(const T2& b); T& operator -=(T& a, const T2& b);
乘法赋值 a = b T& T::operator =(const T2& b); T& operator =(T& a, const T2& b);
除法赋值 a /= b T& T::operator /=(const T2& b); T& operator /=(T& a, const T2& b);
取模赋值 a %= b T& T::operator %=(const T2& b); T& operator %=(T& a, const T2& b);
逐位与赋值 a &= b T& T::operator &=(const T2& b); T& operator &=(T& a, const T2& b);
逐位或赋值 a |= b T& T::operator |=(const T2& b); T& operator |=(T& a, const T2& b);
逐位异或赋值 a ^= b T& T::operator ^=(const T2& b); T& operator ^=(T& a, const T2& b);
逐位左移赋值 a <<= b T& T::operator <<=(const T2& b); T& operator <<=(T& a, const T2& b);
逐位右移赋值 a >>= b T& T::operator >>=(const T2& b); T& operator >>=(T& a, const T2& b);


- 注意


- 所有内建赋值运算符都返回 this,而大多数用户定义重载亦返回 *this,从而能以与内建版本相同的方式使用用户定义运算符。然而,用户定义运算符重载中,能以任何类型为返回类型(包括 void)。
- T2 可为包含 T 在内的任何类型

解释

复制赋值运算符b 内容的副本替换对象 a 的内容(不修改 b)。对于类类型,这是一种特殊成员函数,描述于复制赋值运算符


移动赋值运算符b 的内容替换对象 a 的内容,并尽可能避免复制(可以修改 b)。对于类类型,这是一种特殊成员函数,描述于移动赋值运算符。 (C++11 起)
(C++11 起)

对于非类类型,对复制与移动赋值不加以区分,均被称作直接赋值(direct assignment)

复合赋值(compound assignment)运算符以 a 的值和 b 的值间的二元运算结果替换对象 a 的内容。

内建的直接赋值

直接赋值表达式的形式为

lhs = rhs (1)
lhs = {} (2) (C++11 起)
lhs = { rhs } (3) (C++11 起)

对于内建运算符,lhs 可拥有任何非 const 标量类型,而 rhs 必须可隐式转换为 lhs 的类型。

直接赋值运算符期待以一个可修改左值为其左操作数,以一个右值表达式或花括号初始化器列表 (C++11 起)为其右操作数,并返回一个标识修改后的左运操作的左值。

对于非类类型,首先将右操作数隐式转换为左操作数的无 cv 限定的类型,然后复制其值到左操作数所标识的对象中。

当左操作数拥有引用类型时,赋值运算符修改被引用的对象。

若左右操作数标识的对象之间有重叠,则行为未定义(除非二者严格重叠且类型相同)。


当右运算数为花括号初始化器列表 (brace-init-list)


- 若表达式 E1 拥有标量类型,则


-
- 表达式 E1 = {} 等价于 E1 = T{},其中 TE1 的类型。
- 表达式 E1 = {E2} 等价于 E1 = T{E2},其中 TE1 的类型。


- 若表达式 E1 拥有类类型,则语法 E1 = {args…} 生成以花括号初始化器列表为实参对赋值运算符的一次调用,然后遵循重载决议规则选取适合的赋值运算符。需要注意的是,若以某个非类类型为实参的非模板赋值运算符可用,则它胜过 E1 = {} 中的复制/移动赋值,这是因为从 {} 到非类类型属于恒等转换,它优先于从 {} 到类类型的用户定义转换。
(C++11 起)

以 volatile 限定的非类类型左值为内建直接赋值运算符的左操作数被弃用,除非该赋值表达式出现于不求值语境或是弃值表达式
(C++20 起)

针对用户定义运算符的重载决议中,对于每个类型 T,下列函数签名参与重载决议:


T& operator=(T&, T);

Tvolatile & operator=(Tvolatile &, T);

对于每个枚举或成员指针类型 T(可选地有 volatile 限定),下列函数签名参与重载决议:


T& operator=(T&, T );

对于每对 A1 和 A2,其中 A1 是算术类型(可选地有 volatile 限定)而 A2 是提升后的算术类型,下列函数签名参与重载决议:


A1& operator=(A1&, A2);

示例

运行此代码

  1. #include <iostream>
  2. int main()
  3. {
  4. int n = 0; // 不是赋值
  5. n = 1; // 直接赋值
  6. std::cout << n << ' ';
  7. n = {}; // 零初始化,然后赋值
  8. std::cout << n << ' ';
  9. n = 'a'; // 整型提升,然后赋值
  10. std::cout << n << ' ';
  11. n = {'b'}; // 显式转型,然后赋值
  12. std::cout << n << ' ';
  13. n = 1.0; // 浮点转换,然后赋值
  14. std::cout << n << ' ';
  15. // n = {1.0}; // 编译错误(窄化转换)
  16.  
  17. int& r = n; // 不是赋值
  18. int* p;
  19.  
  20. r = 2; // 通过引用赋值
  21. std::cout << n << '\n';
  22. p = &n; // 直接赋值
  23. p = nullptr; // 空指针转换,然后赋值
  24.  
  25. struct {int a; std::string s;} obj;
  26. obj = {1, "abc"}; // 从花括号初始化器列表赋值
  27. std::cout << obj.a << ':' << obj.s << '\n';
  28. }

输出:

  1. 1 0 97 98 1 2
  2. 1:abc

内建的复合赋值

复合赋值表达式的形式为

lhs op rhs (1)
lhs op {} (2) (C++11 起)
lhs op {rhs} (3) (C++11 起)
op - *=、/=、%=、+=、-=、<<=、>>=、&=、^=、|= 之一
lhs - 对于内建运算符,lhs 可具有任何算术类型,但若 op 为 += 或 -=,则也接受指针类型,并与 + 和 - 有相同限制
rhs - 对于内建运算符,rhs 必须可隐式转换为 lhs

每个内建复合赋值运算符表达式 E1 op= E2(其中 E1 是可修改左值表达式,而 E2 是右值表达式或花括号初始化器列表 (C++11 起))的行为与表达式 E1 = E1 op E2 的行为严格相同,但只对表达式 E1 进行一次求值,并且对于顺序不确定的函数而言是一次单个操作(例如 f(a += b, g()) 中,从 g() 内来看,+= 要么完全未开始,要么已完成)。


以 volatile 限定的非类类型左值为内建复合赋值运算符的左操作数被弃用。
(C++20 起)

针对用户定义运算符的重载决议中,对每对 A1 和 A2,其中 A1 是算术类型(可选地有 volatile 限定)而 A2 为提升后的算术类型,下列函数签名参与重载决议:


A1& operator*=(A1&, A2);

A1& operator/=(A1&, A2);

A1& operator+=(A1&, A2);

A1& operator-=(A1&, A2);

对于每对 I1 与 I2,其中 I1 是整型类型(可选地有 volatile 限定)而 I2 为提升后的整型类型,下列函数签名参与重载决议:


I1& operator%=(I1&, I2);

I1& operator<<=(I1&, I2);

I1& operator>>=(I1&, I2);

I1& operator&=(I1&, I2);

I1& operator^=(I1&, I2);

I1& operator|=(I1&, I2);

对于每个可选地有 cv 限定的对象类型 T,下列函数签名参与重载决议:


T& operator+=(T&, std::ptrdiff_t);

T& operator-=(T&, std::ptrdiff_t);

Tvolatile & operator+=(Tvolatile &, std::ptrdiff_t);

Tvolatile & operator-=(Tvolatile &, std::ptrdiff_t);

示例

本节未完成原因:暂无示例

运算符优先级

运算符重载

常见运算符
赋值 自增自减 算术 逻辑 比较 成员访问 其他

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

++a—aa++a—

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

!aa && ba || b

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

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

a(…)a, b? :
特殊运算符

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 起)