Namespaces
Variants

Assignment operators

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

运算符名称 语法 可重载 原型示例(针对 class T
类内定义 类外定义
简单赋值 a = b T & T :: operator = ( 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 ) ;
按位右移赋值 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 的值之间二元运算的结果。

赋值运算符语法

赋值表达式具有以下形式

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

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

(since 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-expr new-value 标识的对象存在重叠,则行为未定义(除非重叠完全一致且类型相同)。

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

(since C++20)


来自非表达式初始化子句的赋值

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

  • target-expr 标量类型 T ,且 new-value 为空或仅有一个元素。此时,给定一个声明并初始化为 T t = new-value  的虚构变量 t ,则 x = new-value  的含义等同于 x = t
  • target-expr 是类类型。此时, new-value 将作为参数传递给通过 重载解析 选定的赋值运算符函数。
#include <complex>
std::complex<double> z;
z = {1, 2};  // 含义 z.operator=({1, 2})
z += {1, 2}; // 含义 z.operator+=({1, 2})
int a, b;
a = b = {1}; // 含义 a = b = 1;
a = {1} = b; // 语法错误
(C++11 起)

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

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

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

T & operator = ( T & , T ) ;

对于每一对 A1 A2 ,其中 A1 是算术类型(可带有 volatile 限定符)且 A2 是提升后的算术类型,以下函数签名会参与重载决议:

A1 & operator = ( A1 & , A2 ) ;

内置复合赋值运算符

每个内置复合赋值表达式 target-expr op  = new-value 的行为与表达式 target-expr = target-expr op new-value 的行为完全相同,唯一的区别在于 target-expr 仅会被计算一次。

对于内置简单赋值运算符的 target-expr new-value 要求同样适用。此外:

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

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

A1 & operator * = ( A1 & , A2 ) ;
A1 & operator / = ( A1 & , A2 ) ;
A1 & operator + = ( A1 & , A2 ) ;
A1 & operator - = ( A1 & , A2 ) ;
(注:根据要求,所有HTML标签、属性及 标签内的C++代码均保持原样未翻译,仅对页面说明性文字进行了翻译。由于提供的网页内容中不包含需要翻译的自然语言文本,故输出内容与原文完全一致。)

对于每一对 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 ) ;
说明:根据要求,所有HTML标签、属性以及 标签内的C++代码均保持原样未翻译。该表格展示的是C++复合赋值运算符的函数声明,这些专业术语按规则不予翻译。

对于每个可选地带有 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 ) ;
**说明:** - 所有C++代码片段(位于` `标签内)均按规则保留原文 - HTML标签及属性(如`class="t-dcl-begin"`)保持原样 - 表格结构及空白单元格完全保留 - 仅对非代码部分进行翻译(本例中无需要翻译的文本内容)

示例

#include <iostream>
int main()
{
    int n = 0;        // 非赋值操作
    n = 1;            // 直接赋值
    std::cout << n << ' ';
    n = {};           // 零初始化后赋值
    std::cout << n << ' ';
    n = 'a';          // 整型提升后赋值
    std::cout << n << ' ';
    n = {'b'};        // 显式转换后赋值
    std::cout << n << ' ';
    n = 1.0;          // 浮点转换后赋值
    std::cout << n << ' ';
//  n = {1.0};        // 编译错误(窄化转换)
    int& r = n;       // 非赋值操作
    r = 2;            // 通过引用赋值
    std::cout << n << ' ';
    int* p;
    p = &n;           // 直接赋值
    p = nullptr;      // 空指针转换后赋值
    std::cout << p << ' ';
    struct { int a; std::string s; } obj;
    obj = {1, "abc"}; // 从花括号初始化列表赋值
    std::cout << obj.a << ':' << obj.s << '\n';
}

可能的输出:

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

缺陷报告

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

缺陷报告 应用于 发布时的行为 正确行为
CWG 1527 C++11 对类类型对象进行赋值时,仅当赋值操作由用户定义的赋值运算符定义时,右操作数才可以是初始化器列表 移除用户定义赋值的约束条件
CWG 1538 C++11 E1 = { E2 } 等价于 E1 = T ( E2 )
T E1 的类型),这会引入 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_cast const_cast reinterpret_cast 将一种类型转换为另一种类型
new 创建具有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象并释放获取的内存区域
sizeof 查询类型的大小
sizeof... 查询 参数包 的大小 (C++11 起)
typeid 查询类型的类型信息
noexcept 检查表达式是否能抛出异常 (C++11 起)
alignof 查询类型的对齐要求 (C++11 起)

C 文档 关于 赋值运算符