命名空间
变体
操作

赋值运算符

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
表达式
替代表示
字面量
布尔 - 整数 - 浮点
字符 - 字符串 - nullptr (C++11)
用户定义 (C++11)
实用工具
特性 (Attributes) (C++11)
类型
typedef 声明
类型别名声明 (C++11)
类型转换
内存分配
类特定的函数属性
explicit (C++11)
static

特殊成员函数
模板
杂项
 
 

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

运算符名称 语法 可重载 原型示例 (对于 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

目录

[编辑] 定义

复制赋值 将对象 a 的内容替换为 b 内容的副本(b 不会被修改)。对于类类型,这是在一个特殊的成员函数中执行的,在 复制赋值运算符 中描述。

移动赋值 将对象 a 的内容替换为 b 的内容,如果可能则避免复制(b 可能会被修改)。对于类类型,这是在一个特殊的成员函数中执行的,在 移动赋值运算符 中描述。

(自 C++11 起)

对于非类类型,复制和移动赋值是无法区分的,并且被称为直接赋值

复合赋值 将对象 a 的内容替换为 a 的先前值与 b 的值之间的二元运算结果。

[编辑] 赋值运算符语法

赋值表达式具有以下形式

target-expr = new-value (1)
target-expr op new-value (2)
target-expr - 要赋值的表达式[1]
op - 以下之一:*=, /= %=, += -=, <<=, >>=, &=, ^=, |=
new-value - 要赋值给目标的表达式[2](直到 C++11)初始化器子句(自 C++11 起)
  1. target-expr 必须具有比赋值表达式更高的优先级
  2. new-value 不能是逗号表达式,因为它的优先级较低。
1) 简单赋值表达式。
2) 复合赋值表达式。

如果 new-value 不是表达式,则赋值表达式将永远不会匹配重载的复合赋值运算符。

(自 C++11 起)

[编辑] 内置简单赋值运算符

对于内置简单赋值,target-expr 必须是可修改的左值。

target-expr 引用的对象通过将其值替换为 new-value 的结果来修改。如果引用的对象是整数类型 T,并且 new-value 的结果是相应的有符号/无符号整数类型,则对象的值将替换为类型 T 的值,该值具有与 new-value 结果相同的值表示。

内置简单赋值的结果是 target-expr 类型的左值,引用 target-expr。如果 target-expr位域,则结果也是位域。

[编辑] 从表达式赋值

如果 new-value 是表达式,则它会隐式转换target-expr 的 cv-无限定类型。当 target-expr 是一个不能表示表达式值的位域时,位域的结果值是实现定义的。

如果 target-exprnew-value 标识重叠的对象,则行为是未定义的(除非重叠是精确的且类型相同)。

如果 target-expr 的类型是 volatile 限定的,则赋值已弃用,除非(可能带括号的)赋值表达式是discarded-value 表达式未求值操作数

(自 C++20 起)


从非表达式初始化器子句赋值

仅在以下情况下,new-value 才允许不是表达式

  • target-expr标量类型 T,并且 new-value 为空或只有一个元素。在这种情况下,给定一个发明的变量 t,声明并初始化为 T t = new-value x = new-value  的含义是 x = t
  • target-expr 是类类型。在这种情况下,new-value 作为参数传递给由重载决议选择的赋值运算符函数。
#include <complex>
 
std::complex<double> z;
z = {1, 2};  // meaning z.operator=({1, 2})
z += {1, 2}; // meaning z.operator+=({1, 2})
 
int a, b;
a = b = {1}; // meaning a = b = 1;
a = {1} = b; // syntax error
(自 C++11 起)

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

T*& operator=(T*&, T*);
T*volatile & operator=(T*volatile &, T*);

对于每种枚举或指向成员类型的指针 T,可选地 volatile 限定,以下函数签名参与重载决议

T& operator=(T&, T);

对于每对 A1A2,其中 A1 是算术类型(可选 volatile 限定),A2 是提升的算术类型,以下函数签名参与重载决议

A1& operator=(A1&, A2);

[编辑] 内置复合赋值运算符

每个内置复合赋值表达式 target-expr op = new-value 的行为与表达式 target-expr = target-expr op new-value 的行为完全相同,除了 target-expr 只被求值一次。

内置简单赋值运算符对 target-exprnew-value 的要求也适用。此外

  • 对于 +=-=target-expr 的类型必须是算术类型或指向(可能 cv 限定的)完全定义的对象类型的指针。
  • 对于所有其他复合赋值运算符,target-expr 的类型必须是算术类型。

针对用户定义的运算符的重载决议中,对于每对 A1A2,其中 A1 是算术类型(可选 volatile 限定),A2 是提升的算术类型,以下函数签名参与重载决议

A1& operator*=(A1&, A2);
A1& operator/=(A1&, A2);
A1& operator+=(A1&, A2);
A1& operator-=(A1&, A2);

对于每对 I1I2,其中 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);
T*volatile & operator+=(T*volatile &, std::ptrdiff_t);
T*volatile & operator-=(T*volatile &, std::ptrdiff_t);

[编辑] 示例

#include <iostream>
 
int main()
{
    int n = 0;        // not an assignment
 
    n = 1;            // direct assignment
    std::cout << n << ' ';
 
    n = {};           // zero-initialization, then assignment
    std::cout << n << ' ';
 
    n = 'a';          // integral promotion, then assignment
    std::cout << n << ' ';
 
    n = {'b'};        // explicit cast, then assignment
    std::cout << n << ' ';
 
    n = 1.0;          // floating-point conversion, then assignment
    std::cout << n << ' ';
 
//  n = {1.0};        // compiler error (narrowing conversion)
 
    int& r = n;       // not an assignment
    r = 2;            // assignment through reference
    std::cout << n << ' ';
 
    int* p;
    p = &n;           // direct assignment
    p = nullptr;      // null-pointer conversion, then assignment
    std::cout << p << ' ';
 
    struct { int a; std::string s; } obj;
    obj = {1, "abc"}; // assignment from a braced-init-list
    std::cout << obj.a << ':' << obj.s << '\n';
}

可能的输出

1 0 97 98 1 2 (nil) 1:abc

[编辑] 缺陷报告

以下行为变更缺陷报告已追溯应用于先前发布的 C++ 标准。

DR 应用于 已发布行为 正确行为
CWG 1527 C++11 对于类类型对象的赋值,右操作数
只有当赋值由用户定义的
赋值运算符定义时,才能是初始化器列表
移除用户定义的
赋值约束
CWG 1538 C++11 E1 = {E2} 等价于 E1 = T(E2)
TE1 的类型),这引入了一个 C 风格的强制类型转换
它等价于
E1 = T{E2}
CWG 2654 C++20 volatile 限定类型的复合赋值运算符
-不一致地被弃用
它们都不是
被弃用
CWG 2768 C++11 从非表达式初始化器子句赋值
给标量值会执行直接列表初始化
执行复制列表
初始化替代
CWG 2901 C++98 通过 int 左值赋给 unsigned int
对象的值不明确
已明确
P2327R1 C++20 volatile 类型的按位复合赋值运算符
在某些平台上被弃用,但仍然有用
它们不被
弃用

[编辑] 参见

运算符优先级

运算符重载

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

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 语言文档 关于 赋值运算符