赋值运算符

语法

expression assignment-operator expression

assignment-operator:以下项之一
=*=/=%=+=-=<<=>>=&=^=|=

备注

赋值运算符将值存储在左操作数指定的对象中。 有两种赋值运算:

  • 简单赋值,将第二个操作数的值存储在由第一个操作数指定的对象中。

  • 复合赋值,在存储结果之前执行算术、移位或位运算。

下表中除 = 运算符之外的所有其他赋值运算符都是复合赋值运算符。

赋值运算符表

运算符 含义
= 将第二个操作数的值存储在由第一个操作数指定的对象中(简单赋值)。
*= 将第一个操作数的值与第二个操作数的值相乘;将结果存储在第一个操作数指定的对象中。
/= 将第一个操作数的值与第二个操作数的值相除;将结果存储在第一个操作数指定的对象中。
%= 对第二个操作数的值所指定的第一个操作数进行取模;将结果存储在第一个操作数指定的对象中。
+= 将第二个操作数的值与第一个操作数的值相加;将结果存储在第一个操作数指定的对象中。
-= 将第一个操作数的值减去第二个操作数的值;将结果存储在第一个操作数指定的对象中。
<<= 将第一个操作数的值按第二个操作数的值指定的位数左移;将结果存储在第一个操作数指定的对象中。
>>= 将第一个操作数的值按第二个操作数的值指定的位数右移;将结果存储在第一个操作数指定的对象中。
&= 获取第一个和第二个操作数的按位“与”;将结果存储在第一个操作数指定的对象中。
^= 获取第一个和第二个操作数的按位“异或”;将结果存储在第一个操作数指定的对象中。
|= 获取第一个和第二个操作数的按位“与或”;将结果存储在第一个操作数指定的对象中。

运算符关键字

三个复合赋值运算符具有关键字等效项。 它们分别是:

操作员 等效
&= and_eq
|= or_eq
^= xor_eq

C++ 将这些运算符关键字指定为复合赋值运算符的替代拼写。 在 C 中,替代拼写在 <iso646.h> 标头中作为宏提供。 在 C++ 中,备选拼写是关键字;不推荐使用 <iso646.h> 或 C++ 等效的 <ciso646>。 在 Microsoft C++ 中,需要 /permissive-/Za 编译器选项才能启用备选拼写。

示例

// expre_Assignment_Operators.cpp
// compile with: /EHsc
// Demonstrate assignment operators
#include <iostream>
using namespace std;
int main() {
   int a = 3, b = 6, c = 10, d = 0xAAAA, e = 0x5555;

   a += b;      // a is 9
   b %= a;      // b is 6
   c >>= 1;      // c is 5
   d |= e;      // Bitwise--d is 0xFFFF

   cout  << "a = 3, b = 6, c = 10, d = 0xAAAA, e = 0x5555" << endl
         << "a += b yields " << a << endl
         << "b %= a yields " << b << endl
         << "c >>= 1 yields " << c << endl
         << "d |= e yields " << hex << d << endl;
}

简单赋值

简单赋值运算符 (=) 使第二个操作数的值存储在第一个操作数指定的对象中。 如果两个对象都是算术类型,则在存储值之前,正确的操作数将转换为左侧的类型。

constvolatile 类型的对象可以赋给仅为 volatile 或不为 constvolatile 的类型的左值。

对类类型(structunionclass 类型)的对象的赋值由名为 operator= 的函数执行。 此运算符函数的默认行为是执行对象的非静态数据成员和直接基类的逐个成员复制赋值;不过,可使用重载运算符修改此行为。 有关详细信息,请参阅运算符重载。 类类型还可以具有复制赋值移动赋值运算符。 有关详细信息,请参阅复制构造函数和复制赋值运算符移动构造函数和移动赋值运算符

任何从给定基类明确派生的类的对象均可赋给基类的对象。 反之则不然,因为有一个隐式转换,它能从派生类转换到基类,但不能从基类转换到派生类。 例如:

// expre_SimpleAssignment.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class ABase
{
public:
    ABase() { cout << "constructing ABase\n"; }
};

class ADerived : public ABase
{
public:
    ADerived() { cout << "constructing ADerived\n"; }
};

int main()
{
    ABase aBase;
    ADerived aDerived;

    aBase = aDerived; // OK
    aDerived = aBase; // C2679
}

对引用类型的赋值的行为方式就像对引用所指向的对象进行赋值一样。

对于类类型对象,赋值与初始化不同。 若要演示不同赋值和初始化的工作方式,请考虑以下代码

UserType1 A;
UserType2 B = A;

上面的代码显示了一个初始值设定项;它调用了采用 UserType2 类型的自变量的 UserType1 的构造函数。 给定以下代码

UserType1 A;
UserType2 B;

B = A;

赋值语句

B = A;

可能具有以下效果之一:

  • UserType2 调用函数 operator=,前提是为 operator= 提供了 UserType1 参数。

  • 如果存在显式转换函数 UserType1::operator UserType2,则调用该函数。

  • 调用采用 UserType2::UserType2 参数并复制结果的构造函数 UserType1,前提是存在此类构造函数。

复合赋值

复合赋值运算符显示在赋值运算符表中。 这些运算符具有 e1op= e2 的形式,其中 e1 为非 const 可修改左值,e2 为:

  • 算术类型

  • 指针(如果 op+-

  • 存在与 e1 类型匹配的 operator *op*= 重载的类型

内置 e1op= e2 形式的行为与 e1=e1ope2 的相同,但是只计算一次 e1。

对枚举类型的复合赋值将生成错误消息。 如果左操作数属于指针类型,则右操作数必须属于指针类型或必须是计算结果为 0 的常量表达式。 左操作数属于整数类型时,右操作数不能属于指针类型。

内置赋值运算符的结果

内置赋值运算符返回赋值后左操作数指定的对象值(在复合赋值运算符中,还会返回算术/逻辑运算)。 获得的类型是左操作数的类型。 赋值表达式的结果始终为左值。 这些运算符具有从右向左的关联性。 左操作数必须为可修改的左值。

在 ANSI C 中,赋值表达式的结果不是左值。 这意味着 C 中不允许使用合法的 C++ 表达式 (a += b) += c

另请参阅

带二元运算符的表达式
C++ 内置运算符、优先级和关联性
C 赋值运算符