Skip to content

C++ 运算符

运算符(operator)是一个符号,它指示编译器执行特定的数学、逻辑或操作运算。C++ 提供了一套丰富的内置运算符,主要分类如下:

  • 算术运算符 (Arithmetic Operators)
  • 关系运算符 (Relational Operators)
  • 逻辑运算符 (Logical Operators)
  • 位运算符 (Bitwise Operators)
  • 赋值运算符 (Assignment Operators)
  • 杂项运算符 (Miscellaneous Operators)(包括三元条件运算符、sizeof、类型转换、指针等)

本章将探讨这些运算符。

这些运算符执行标准的数学计算。

假设 int a = 10; 且 int b = 20;

运算符名称描述示例
+加法将两个操作数相加a + b // 结果是 30
-减法用第一个操作数减去第二个操作数b - a // 结果是 10
*乘法将两个操作数相乘a * b // 结果是 200
/除法用第一个操作数除以第二个操作数。如果两个操作数都是整数,则结果为整数。b / a // 结果是 2
%取模计算整数除法的余数b % a // 结果是 0
++自增将整数值增加一。前置自增 (++a) 在使用前增加,后置自增 (a++) 在使用后增加。++a // a 变为 11, 结果是 11
a++ // a 变为 11, 结果是 10 (原始值)
—自减将整数值减少一。前置/后置行为与自增类似。—a // a 变为 9, 结果是 9
a— // a 变为 9, 结果是 10 (原始值)

这些运算符比较两个操作数并返回一个布尔值 (true 或 false)。

假设 int a = 10; 且 int b = 20;

运算符名称描述示例
==等于检查两个操作数的值是否相等。(a == b) // 假
!=不等于检查两个操作数的值是否不相等。(a != b) // 真
>大于检查左操作数的值是否大于右操作数。(a > b) // 假
<小于检查左操作数的值是否小于右操作数。(a < b) // 真
>=大于或等于检查左操作数的值是否大于或等于右操作数。(a >= b) // 假
<=小于或等于检查左操作数的值是否小于或等于右操作数。(a <= b) // 真

注意:C++20 引入了三路比较运算符 (<=>),也称为飞船运算符 (spaceship operator),它可以简化比较逻辑,但这些基本运算符仍然是必不可少的。

这些运算符作用于布尔操作数,通常用于组合关系表达式。

假设 bool condition1 = true; 且 bool condition2 = false;

运算符名称描述示例
&&逻辑与仅当两个操作数都为 true 时,结果才为 true。使用短路求值(如果第一个操作数为 false,则不评估第二个)。(condition1 && condition2) // 假
||逻辑或如果至少有一个操作数为 true,则结果为 true。使用短路求值(如果第一个操作数为 true,则不评估第二个)。(condition1 || condition2) // 真
!逻辑非反转操作数的逻辑状态。true 变为 false,false 变为 true。!condition1 // 假
!condition2 // 真

这些运算符直接操作整数操作数的二进制(位)表示。

基本位运算的真值表:

pqp & q (AND)p | q (OR)p ^ q (XOR)
00000
01011
11110
10011

假设 unsigned int a = 60;(二进制 0011 1100)且 unsigned int b = 13;(二进制 0000 1101)。使用 unsigned int 可以避免此示例中的符号扩展复杂性。

a = 0011 1100
b = 0000 1101
-----------------
a & b = 0000 1100 (十进制 12)
a | b = 0011 1101 (十进制 61)
a ^ b = 0011 0001 (十进制 49)
~a = 1100 0011 (取决于 int 大小和符号性;对于无符号 8 位:195。对于使用二进制补码的有符号 8 位,它可能表示 -61)
运算符名称描述示例 (使用 a=60, b=13)
&按位与如果两个操作数中都存在某位,则将该位复制到结果中。(a & b) // 结果是 12 (0000 1100)
|按位或如果任一操作数中存在某位,则将该位复制。(a | b) // 结果是 61 (0011 1101)
^按位异或如果仅在一个操作数中设置了某位,则复制该位。(a ^ b) // 结果是 49 (0011 0001)
~按位取反一元运算符;翻转其操作数的所有位。(~a) // 结果取决于整数大小和符号性。对于 32 位无符号 int,它是一个很大的正数。对于有符号 int,通常由于二进制补码而导致结果为 -(a+1)。
<<左移将左操作数的位向左移动右操作数指定的位数。用零填充空出的位。a << 2 // 结果是 240 (1111 0000)
>>右移将左操作数的位向右移动。对于有符号类型,最左侧空出的位的行为是实现定义的(通常是符号位复制 - 算术右移),而无符号类型用零填充(逻辑右移)。a >> 2 // 结果是 15 (0000 1111)

这些运算符将值赋给变量。复合赋值运算符提供了常见操作的简写形式。

假设 int c = 0; int a = 10; int b = 20;

运算符名称描述示例
=简单赋值将右操作数的值赋给左操作数。c = a + b; // c 变为 30
+=加并赋值将右操作数加到左操作数,并将结果赋给左操作数。c += a; // 等同于 c = c + a;
-=减并赋值从左操作数中减去右操作数,并将结果赋给左操作数。c -= a; // 等同于 c = c - a;
*=乘并赋值将左操作数乘以右操作数,并将结果赋给左操作数。c *= a; // 等同于 c = c * a;
/=除并赋值将左操作数除以右操作数,并将结果赋给左操作数。c /= a; // 等同于 c = c / a;
%=取模并赋值使用两个操作数计算模,并将结果赋给左操作数。c %= a; // 等同于 c = c % a;
<<=左移并赋值执行按位左移并赋值。c <<= 2; // 等同于 c = c << 2;
>>=右移并赋值执行按位右移并赋值。c >>= 2; // 等同于 c = c >> 2;
&=按位与并赋值执行按位与并赋值。c &= a; // 等同于 c = c & a;
^=按位异或并赋值执行按位异或并赋值。c ^= a; // 等同于 c = c ^ a;
|=按位或并赋值执行按位或并赋值。c |= a; // 等同于 c = c | a;

C++ 中的其他重要运算符:

运算符名称描述示例
sizeofsizeof 运算符返回数据类型或变量的大小(以字节为单位)。结果类型是 size_t。大小可能因平台/编译器而异。sizeof(int) // 返回 int 的大小(例如,4)
sizeof(myVariable) // 返回 myVariable 的大小
?:三元条件运算符语法:条件 ? ValueIfTrue : ValueIfFalse。评估条件。如果为 true,则返回 ValueIfTrue;否则,返回 ValueIfFalse。int maxVal = (a > b) ? a : b;
,逗号运算符顺序评估多个表达式,从左到右。整个表达式的结果是最右边表达式的值。常用于 for 循环中。x = (a++, b++); // 先递增 a,然后递增 b,最后将 b 的原始值赋给 x
. (点) 和 -> (箭头)成员访问运算符. 用于访问对象的成员(变量或函数)。-> 用于通过指向对象的指针访问成员。myObject.member
myPointer->member (等同于 (*myPointer).member)
Casting Operators类型转换将一个数据类型的值转换为另一个。现代 C++ 更倾向于显式转换:static_cast、dynamic_cast、const_cast、reinterpret_cast。避免使用 C 风格转换 ((type)value 或 type(value))。int i = static_cast<int>(2.718); // i 变为 2
float f = static_cast<float>(i);
&取地址运算符一元运算符;返回其操作数的内存地址。int* ptr = &myVariable; // ptr 存储 myVariable 的地址
*解引用运算符一元运算符;访问指针所持有的内存地址处存储的值。int value = *ptr; // value 获取 ptr 指向的内容

运算符优先级决定了表达式中运算符的评估顺序。优先级较高的运算符在优先级较低的运算符之前被评估。结合性定义了具有相同优先级的运算符的评估顺序(从左到右或从右到左)。

例如,在 x = 7 + 3 * 2; 中,乘法 (*) 的优先级高于加法 (+),因此先评估 3 * 2(结果为 6),然后是 7 + 6(结果为 13)。x 变为 13。

使用括号 () 来覆盖优先级或提高清晰度:x = (7 + 3) * 2; 将导致 x 为 20。

以下是 C++ 运算符优先级(从高到低)和结合性的总结:

类别运算符结合性
作用域解析 (Scope Resolution)::从左到右
后缀/主运算符 (Postfix/Primary)() [] . -> ++ -- typeid static_cast dynamic_cast const_cast reinterpret_cast从左到右
一元/前缀运算符 (Unary/Prefix)+ - ! ~ ++ -- * & sizeof new delete (type) noexcept alignof从右到左
成员指针访问 (Member Pointer Access).* ->*从左到右
乘法类运算符 (Multiplicative)* / %从左到右
加法类运算符 (Additive)+ -从左到右
移位运算符 (Shift)<< >>从左到右
三路比较 (C++20) (Three-way comparison)<=>从左到右
关系运算符 (Relational)< <= > >=从左到右
相等性运算符 (Equality)== !=从左到右
按位与 (Bitwise AND)&从左到右
按位异或 (Bitwise XOR)^从左到右
按位或 (Bitwise OR)|从左到右
逻辑与 (Logical AND)&&从左到右
逻辑或 (Logical OR)||从左到右
条件运算符 (三元) (Conditional (Ternary))?:从右到左
赋值运算符 (Assignment)= += -= *= /= %= <<= >>= &= ^= |=从右到左
Throw 表达式 (Throw expression)throw从右到左
逗号运算符 (Comma),从左到右

有关权威的优先级表,请参阅 cppreference.com 等资源。如有疑问,请使用括号!