赋值运算符
赋值运算符修改对象的值。
运算符名 | 语法 | 可重载 | 原型示例(对于 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); |
|
目录 |
[编辑] 解释
复制赋值运算符将对象 a
的内容替换为 b
的内容的一个副本(且不改动 b
)。对于类类型来说,这是一种特殊成员函数,在复制赋值运算符中描述。
移动赋值运算符将对象 a
的内容替换为 b
的内容,尽可能避免进行复制(且可能改动 b
。对于类类型来说,这是一种特殊成员函数,在移动赋值运算符中描述。 (C++11 起)
对于非类类型来说,复制和赋值是不可区分的,并被称为直接赋值。
复合赋值运算符将对象 a
的内容替换为对 a
的前值和 b
的值实施一种二元运算后的结果。
[编辑] 内建的直接赋值
对于每个类型 T
,有如下函数签名参与重载解析:
T*& operator=(T*&, T*); |
||
T*volatile & operator=(T*volatile &, T*); |
||
对于每个(可选地带有 volatile 限定的)枚举或成员指针类型 T
,有如下函数签名参与重载解析:
T& operator=(T&, T ); |
||
对于每对 A1 和 A2,其中 A1 为(可选地带有 volatile 限定的)算术类型而 A2 为提升后的算术类型,有如下函数签名参与重载解析:
A1& operator=(A1&, A2); |
||
对于任何标量类型 T
的表达式 E1,还允许以下额外的内建赋值表达式形式:
E1 = {} |
(C++11 起) | |
E1 = {E2} |
(C++11 起) | |
注:以上包括所有非类类型,但不包括引用类型,数组类型,函数类型,以及 void 类型,它们是不可直接赋值的。
直接赋值运算符期望一个可改动的左值作为其做操作数,和一个右值表达式或一个花括号初始化列表(braced-init-list) (C++11 起)作为其右操作数,并返回标识了修改后的左操作数的左值。
对于非类类型来说,其右操作数首先被隐式转换为左操作数类型的 cv 未限定版本,然后将其值复制到由左操作数所标识的对象之中。
当左操作数具有引用类型时,赋值运算符将改动其所指代的对象。
如果左右操作数标识了互相有重叠的对象,则除非是精确重叠且类型相同,否则其行为未定义。
当右操作数为花括号初始化列表(braced-init-list)时,
|
(C++11 起) |
[编辑] 示例
#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; // 并非赋值 int* p; r = 2; // 通过引用赋值 std::cout << n << ' '; p = &n; // 直接赋值 p = nullptr; // 空指针转换,然后赋值 struct {int a; std::string s;} obj; obj = {1, "abc"}; // 以花括号初始化列表进行赋值 std::cout << obj.a << ':' << obj.s << '\n'; }
输出:
1 0 97 98 1 2
[编辑] 内建的复合赋值
对于每对 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); |
||
T*volatile & operator+=(T*volatile &, std::ptrdiff_t); |
||
T*volatile & operator-=(T*volatile &, std::ptrdiff_t); |
||
每个内建的复合赋值表达式 E1 op= E2(其中 E1 为可改动左值表达式而 E2 为右值表达式或花括号初始化列表(braced-init-list) (C++11 起)),其行为与表达式 E1 = E1 op E2 的行为完全相同,但表达式 E1
仅会被求值一次,并且对于顺序不确定的函数调用来说,它表现为一次单独的运算(例如,在 f(a += b, g()) 中,g() 之内所见的 += 要么根本尚未开始要么已经完成)。
[编辑] 示例
本节未完成 原因:暂无示例 |
[编辑] 另请参阅
常见运算符 | ||||||
---|---|---|---|---|---|---|
赋值 | 自增 自减 |
算术 | 逻辑 | 比较 | 成员访问 | 其他 |
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |
特殊运算符 | ||||||
static_cast 转换一个类型为另一相关类型 |