运算符
介绍了变量和常量,我们就可以开始使用运算符来操作它们了。
以下是完整的运算符列表。
可能我们没有必要知道所有这些运算符,
但它们都列在这里,可以作为参考
☞ 赋值运算符 (=)
赋值运算符可以为变量赋值。
此语句将整数5赋值给变量x。赋值操作从右到左进行,而不是相反:
此语句将变量y中的值赋值变量x。x的值在此语句执行时被y值替换。
赋值操作只在此语句执行时才把y的值赋给x。因此,如果y稍后更改,新值则不会影响x的值。
例如,让我们看下面的代码 - 存储在变量中的内容的变化在注释中:
// assignment operator
#include <iostream>
using namespace std;
int main ()
{
int a, b; // a:?, b:?
a = 10; // a:10, b:?
b = 4; // a:10, b:4
a = b; // a:4, b:4
b = 7; // a:4, b:7
cout << "a:";
cout << a;
cout << " b:";
cout << b;
}
|
a:4 b:7
|
该程序在屏幕上打印a和b(分别为 4 和 7)的最终值。
注意 a没有受到 b 的最终修改的影响,即使我们之前声明过a = b。
赋值操作可以是求值的表达式。
这意味着赋值表达式本身有一个值,对于基本类型,这个值就是在操作中被赋值的值。
例如:
在这个表达式中,y被赋值为 2 加上另一个赋值表达式的值(它的值为 5)的结果。
它大致相当于:
y的最终结果。
以下表达式在 C++ 中也有效:
它将 5 从右到左依次分配给三个变量:z和y,x;
☞ 算术运算符 ( +, -, *, /, % )
C++支持五种算术运算:
操作符 |
说明 |
+ |
加 |
- |
减 |
* |
乘 |
/ |
除 |
% |
取模 |
加法、减法、乘法和除法运算在字面上对应于它们各自的数学运算符。
最后一个,模运算符,用百分号 ( %) 表示,得出两个值相除的余数。
例如:
变量x结果为 2,因为 11 除以 3 ,商为 3,余数为 2。
☞ 复合赋值运算符(+=、-=、*=、/=、%=、>>=、<<=、&=、^=、|=)
通过对复合赋值运算符执行操作来修改变量的当前值。
它们等效于将运算结果赋值给第一个操作数:
表达式 |
同等操作 |
y += x; |
y = y + x; |
x -= 5; |
x = x - 5; |
x /= y; |
x = x / y; |
price *= units + 1; |
price = price * (units+1); |
其他复合赋值运算符也是如此。
例如:
// compound assignment operators
#include <iostream>
using namespace std;
int main ()
{
int a, b=3;
a = b;
a+=2; // equivalent to a=a+2
cout << a;
}
|
5
|
☞ 递增和递减 (++, --)
某些表达式可以进一步缩简:
递增运算符 ( ++) 和递减运算符 ( --) 将存储在变量中的值增加或减少 1。
它们分别相当于+=1和-=1。因此:
在功能上都是等价的;他们都是将 x 的值加 1。
在早期的 C 编译器中,前面的三个表达式可能会产生不同的可执行代码,
具体取决于使用的是哪个编译器。
现在这种类型的代码优化一般是由编译器自动执行的,
因此这三个表达式应该产生完全相同的可执行代码。
这种运算符的一个特点是它既可以用作前缀也可以用作后缀。
这意味着它可以写在变量名 ( ++x) 之前或之后 ( x++)。
在简单的表达方式中,例如x++或++x, 两者含义完全相同;
在计算递增或递减运算结果的其他表达式中,它们的含义可能存在重要差异:
在使用递增运算符作为值的前缀 ( ++x) 的情况下,
表达式的计算结果为最终的值x。
另一方面,如果将其用作后缀 ( x++),则x的值也会增加,
但是表达式的计算结果为 x 增加之前的值。注意区别:
示例 1 |
示例 2 |
x = 3;
y = ++x;
// x contains 4, y contains 4
|
x = 3;
y = x++;
// x contains 4, y contains 3
|
在例1中,y被赋予的值是x增加后的值。而在示例 2 中,它是x增加之前的值。
☞ 关系和比较运算符 ( ==, !=, >, <, >=, <= )
可以使用关系运算符和相等运算符比较两个表达式。
例如,要想知道两个值是否相等或一个值是否大于另一个值。
此类操作的结果为真或假(即布尔值)。
C++中的关系运算符是:
操作符 |
说明 |
== |
等于 |
!= |
不等于 |
< |
小于 |
> |
大于 |
<= |
小于或等于 |
>= |
大于或等于 |
实例:
(7 == 5) // evaluates to false
(5 > 4) // evaluates to true
(3 != 2) // evaluates to true
(6 >= 6) // evaluates to true
(5 < 5) // evaluates to false
|
当然,不仅可以比较数字常量,还可以比较任何值,
当然包括变量。假设a=2,b=3和c=6, 那么
(a == 5) // evaluates to false, since a is not equal to 5
(a*b >= c) // evaluates to true, since (2*3 >= 6) is true
(b+4 > a*c) // evaluates to false, since (3+4 > 2*6) is false
((b=2) == a) // evaluates to true
|
注意!赋值运算符( = ,一个等号)与相等比较运算符( == ,两个等号)不同;
第一个 ( =) 将右边的值赋给左边的变量,而另一个 ( ==) 比较运算符两边的值是否相等。
因此,在最后一个表达式 ( (b=2) == a) 中,我们首先将值2赋值给b,
然后将其与a(也存储值 2)进行比较,从而结果为true。
☞ 逻辑运算符 ( !, &&, || )
运算符!是布尔运算 NOT 的 C++ 运算符。
它只有一个运算符,在操作数的右边,并将操作数的值取反,
如果它的操作数是true,则结果为false,反之亦然。
基本上,它返回其操作数的相反布尔值。例如:
!(5 == 5) // evaluates to false because the expression at its right (5 == 5) is true
!(6 <= 4) // evaluates to true because (6 <= 4) would be false
!true // evaluates to false
!false // evaluates to true
|
逻辑运算符&& 和 || 在表示两个表达式关系时使用。
运算符&&对应于布尔逻辑运算 AND,
如果它的两个操作数都是true,则结果为true,否则为false。
下面显示运算符&&运算表达式a && b的结果:
&& OPERATOR (and) |
a |
b |
a && b |
true |
true |
true |
true |
false |
false |
false |
true |
false |
false |
false |
false |
该运算符||对应于布尔逻辑运算 OR,
如果其任一操作数为true,则结果为true,
因此仅当两个操作数均为false时结果为false。
以下是a||b的结果:
&& OPERATOR (OR) |
a |
b |
a || b |
true |
true |
true |
true |
false |
true |
false |
true |
true |
false |
false |
false |
例如:
( (5 == 5) && (3 > 6) ) // evaluates to false ( true && false )
( (5 == 5) || (3 > 6) ) // evaluates to true ( true || false )
|
当使用逻辑运算符时,c++按从左到右的顺序只计算必要的值,
从而得出整个组合的结果,而忽略其余部分。
例如,在最后一个示例 ( (5==5)||(3>6)) 中,C++ 首先评估5==5是否为true,
如果是true,则不检查3>6是true还是false。这被称为短路判定,
对于这些运算符的运算规则如下:
operator |
短路判定 |
&& |
如果左侧表达式为false,则组合结果为false(永远不会计算右侧表达式)。 |
|| |
如果左侧表达式为true,则组合结果为true(永远不会计算右侧表达式)。 |
请注意短路判定的副作用,如改变值:
if ( (i<10) && (++i<n) ) { /*...*/ } // 注意条件增量 i
|
此处,组合条件表达式将 i 增加 1 ,除非 && 左侧的表达式是true,
否则,永远不会计算右侧 ( ++i<n)的条件.
☞ 条件三元运算符 ( ? )
条件运算符判断一个表达式,
如果该表达式的计算结果为true,则返回一个值,
如果该表达式的计算结果为false,则返回一个不同的值。
它的语法是:
condition ? result1 : result2
如果判断条件(condition)是true,则整个表达式的计算结果为result1,否则为result2。
7==5 ? 4 : 3 // 表达式结果为 3, 因为 7 不等于 5.
7==5+2 ? 4 : 3 // 表达式结果为 4, 因为 7 等于 5+2.
5>3 ? a : b // 表达式结果为 a 的值, 因为 5 大于 3.
a>b ? a : b // 表达式结果取决于那个大, a 或者 b.
|
例如:
// conditional operator
#include <iostream>
using namespace std;
int main ()
{
int a,b,c;
a=2;
b=7;
c = (a>b) ? a : b;
cout << c << '\n';
}
|
结果是 7 .
在这个例子中,a是 2,b是 7,所以被计算的表达式 ( a>b) 不是true,
因此在问号之后的第一个值被丢弃,取而代之的是第二个值(冒号之后的那个),它是b(值 7)。
☞ 逗号运算符 ( , )
逗号运算符 ( ,)
用于分隔包含在只需要一个表达式的位置的两个或多个表达式。
当必须对其中一组表达式求值时,只考虑最右边的表达式。
例如,以下代码:
将首先将值 3 赋值给 b ,然后赋值 b+2 给变量 a 。
因此,最后,变量 a 的值是 5,而变量 b 的值是 3。
☞ 按位运算符 ( &, |, ^, ~, <<, >> )
位运算符会根据它们存储的值的位模式来修改变量。
运算符 |
逻辑运算 |
说明 |
& |
AND |
按位与 |
| |
OR |
按位或 |
^ |
XOR |
按位异或 |
~ |
NOT |
一元补码(取反) |
<< |
SHL |
左移 |
>> |
SHR |
右移 |
☞ 显式类型转换运算符
类型转换运算符允许将给定类型的值转换为另一种类型。
在 C++ 中有几种方法可以做到这一点。最简单的一种,从C语言继承而来,
就是在要转换的表达式之前用括号(())括起来:
int i;
float f = 3.14;
i = (int) f;
|
上面的代码将浮点数 3.14 转换为整数值 ( 3);剩余部分舍
。
在这里,类型转换运算符是(int).
在 C++ 中,另一种方法是在要做类型转换的表达式之前使用类型符号,并将表达式括在括号之间.
这两种类型转换方式在 C++ 中都是有效的。
☞ sizeof
此运算符接受一个参数,该参数可以是类型或变量,并返回该类型或对象的字节大小:
这里,x 被赋值为 1,因为 char 是一个大小为一个字节的类型。
sizeof 返回的值是一个编译时常量,所以它是在程序执行之前确定的。
☞ 其他运算符
后面我们将看到更多的操作符,比如那些指代指针的操作符或面向对象编程的细节.
☞ 运算符的优先级
一个表达式可能有多个运算符。例如:
在 C++ 中,上面的表达式总是给 x 赋值 6,
因为 % 运算符的优先级高于+运算符,所以总是在之前计算。
表达式的一部分可以用括号括起来以覆盖此优先顺序,
或明确说明预期的效果。注意区别:
x = 5 + (7 % 2); // x = 6 (same as without parenthesis)
x = (5 + 7) % 2; // x = 0
|
从最大到最小优先级,C++ 运算符按以下顺序计算:
等级 |
优先级组 |
运算符 |
说明 |
顺序组 |
1 |
作用域 |
:: |
范围限定符 |
左到右 |
2 |
后缀(一元) |
++ -- |
后缀递增/递减 |
左到右 |
() |
功能型 |
[] |
下标 |
. -> |
访问成员 |
3 |
前缀(一元) |
++ -- |
前缀递增/递减 |
右到左 |
~! |
按位非/逻辑非 |
+ - |
一元前缀 |
& * |
引用/取消引用 |
new delete |
分配(allocation)/释放(deallocation) |
sizeof |
度量 |
(type) |
C 风格的类型转换 |
4 |
指向成员的指针 |
.* ->* |
访问指针 |
左到右 |
5 |
数学运算符:缩放 |
* / % |
乘、除、取模 |
左到右 |
6 |
数学运算符:加法 |
+ - |
加法、减法 |
左到右 |
7 |
移位运算符 |
<< >> |
左移,右移 |
左到右 |
8 |
关系型 |
< > <= >= |
比较运算符 |
左到右 |
9 |
相等 |
== != |
等于/不等于 |
左到右 |
10 |
与 |
& |
按位与 |
左到右 |
11 |
独占或 |
^ |
按位异或 |
左到右 |
12 |
兼容或 |
| |
按位或 |
左到右 |
13 |
并且 |
&& |
逻辑与 |
左到右 |
14 |
或者 |
|| |
逻辑或 |
左到右 |
15 |
赋值表达式 |
= *= /= %= += -=
>>= <<= &= ^= |=
|
赋值/复合赋值 |
右到左 |
? : |
条件运算符 |
16 |
排序 |
, |
逗号分隔符 |
左到右 |
当一个表达式有两个具有相同优先级的运算符时,
顺序组确定首先计算哪一个:从左到右或从右到左。
将所有子语句括在括号中,(即使是那些由于优先级而不必要(加括号)的语句)可以提高代码的可读性。