*********************************************************
*********************************************************
操作符
|
一旦我们知道了变量和常量的存在,我们就想要去操作它们。由于这个原因,
C++
引入了操作符。与那些操作符主要是关键字的语言不同,
C++
中的操作符主要是由那些在键盘上可用却不是字母的符号组成的。这使得
C++
代码更短、更国际化,因为它和英语单词有更少的依赖关系,但是也要求在开始的时候下些功夫。
你并不需要这节中的所有内容。大部分的细节都是为你以后需要它的时候做的参考。
赋值
(=)
赋值运算符把一个值指定给一个变量。
a = 5;
|
这条语句把整型值
5
赋给了变量
a
。在赋值运算符左面的叫做
lvalue
(
左值
)
,右面的叫
rvalue
(
右值
)
。左值必须是一个变量,而右值可以是一个常量,或是变量,或是某个运算的结果,或是它们的任何组合。
赋值运算的最重要的规则是从右向左的规则:赋值运算总是从右向左赋值,从来没有其他方式:
a = b;
|
这条语句把变量
b
(
右值
)
中保存得值赋给变量
a
(
左值
)
。这个运算符不会考虑
a
中以前保存的值,事实上这个值被丢弃了。
同时我们仅仅在这时把
b
的值赋给了
a
。因此
b
以后的改变将不会影响到
a
的新值。
例如,让我们看看下面的代码——我已经把变量中保存的值的变化写在了注释中:
// assignation 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;
return 0;
}
|
a:4 b:7
|
这段代码将给我们这样的结果:
a
最终值是
4
,
b
的最终值是
7
。请注意
a
并没有受到
b
最后修改的影响,虽然我们在先前声明了
a = b (
这是因为从右向左规则
)
。
C++
优于其他编程语言的一个特性是:赋值操作可以被用作另一个赋值符的右值
(
或右值的一部分
)
。例如:
a = 2 + (b = 5);
|
与下面相同:
b = 5;
a = 2 + b;
|
这意味着:首先把
5
赋给变量
b
,然后再把
2
加上前一个给
b
赋值的结果
(
也就是
5)
赋给
a
,使
a
的最终值是
7
。
下面的写法在
C++
中也是有效的:
a = b = c = 5;
|
它把
5
赋给了全部三个变量
:
a
,
b
和
c
。
算术操作赋
( +, -, *, /, % )
C++
支持的五个算术操作赋是:
+
|
加
|
-
|
减
|
*
|
乘
|
/
|
除
|
%
|
取模
|
加、减、乘、除操作很它们在数学上的操作符是完全一致的。你唯一可能没见过的操作可能是取模,它的操作赋是百分号
( % )
。取模运算是取两个值相除所得的余数。例如,如果我们写:
a = 11 % 3;
|
变量
a
的值将是
2
,因为
2
是
11
除
3
的余数。
复合赋值
(+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)
当我们想通过操作已经存在于某个变量里的值来修改这个变量的值的时候我们可以使用复合赋值操作符:
表达式
|
等价于
|
value += increase;
|
value = value + increase;
|
a -= 5;
|
a = a - 5;
|
a /= b;
|
a = a / b;
|
price *= units + 1;
|
price = price * (units + 1);
|
另五个与此类似。例如:
// compund assignation
#include <iostream>
using namespace std;
int main ()
{
int a, b=3;
a = b;
a+=2;
// equivalent to a=a+2
cout << a;
return 0;
}
|
5
|
自增和自减
(++, --)
比其他方法更简洁,自增操作符
( ++ )
和自减操作符
( -- )
把保存在一个变量里的值增加或减少一。它们与
+=1
和
-=1
分别等价。因此:
c++;
c+=1;
c=c+1;
|
它们在功能上是相同的:它们三个都是令
c
的值增加一。
在早期的
C
编译器里,根据你使用的是那个,前面的三种表达法将得到不同的可执行代码。在今天,这种类型的代码优化编译器通常是自动完成的,因此这三种表达法将得到完全相同的可执行代码。
这个操作赋的一个特性它既可以被用作前缀也可以被用作后缀。那就意味着它既可以写在一个变量标识符的前面
( ++a )
也可以写在它的后面
( a++ )
。虽然在简单的表达式,例如
a++
或
++a
,它们有完全相同的含义,而在那些自增或自减的结果是另一个表达式的运算数的时候,他们在意义上就有非常大的不同了:在自增运算符被用作前缀
( ++a )
的情况下,
a
的值在使用前先增加;而在自增运算符被用作后缀
(a++ )
的情况下,
a
的值在使用后才增加。注意这些不同:
例子
1
|
例子
2
|
B=3; A=++B; // A contains 4, B contains 4 |
B=3; A=B++; // A contains 3, B contains 4 |
在例子
1
中
, B
在把值赋给
A
之前先自增
.
在例子
2
中
, B
的值先被拷贝到
A
中,然后
B
再自增。
关系和等价运算符
( ==, !=, >, <, >=, <= )
为了比较两个表达式我们可以使用关系和等价运算符。关系和等价运算符的结果为只能是
true
或
false
的布尔值,根据它的布尔结果。
我们想要比较两个表达式,例如,想要知道是否它们是相等的或是否一个比另一个大。这是在
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(
真
)
。
逻辑操作符
( !, &&, || )
操作符
!
是
C++
中的布尔“非”操作,它只有一个操作数,这个操作数放在它的右边,它所作的唯一的一件事就是对操作数的值取非,如果它的操作数是
true
的话结果是
false
,如果它的操作数是
false
的话结果是
true
。基本的,它返回它的操作数的布尔计算结果的对立值。例如:
!(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
的结果:
&&
操作符
a
|
b
|
a && b
|
true
|
true
|
true
|
true
|
false
|
false
|
false
|
true
|
false
|
false
|
false
|
false
|
操作符
||
相当于布尔逻辑运算里的“或
(OR)
”。如它的两个操作数中没有一个是
true
是它的结果是
false
,也只是说它只有在两个操作数都是
false
是结果才是发绿色,下面是
a || b
的可能结果:
||
操作符
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 ).
|
条件操作符
( ? )
条件操作符计算一个表达式,如果表达式为
true
返回一个值;如果表达式为
false
返回临一个值。它的格式为:
condition ? result1 : result2
如果条件为
true
表达式将返回
result1,
如果为
false
则返回
result2
。
7==5 ? 4 : 3
// returns 3, since 7 is not equal to 5.
7==5+2 ? 4 : 3
// returns 4, since 7 is equal to 5+2.
5>3 ? a : b
// returns the value of a, since 5 is greater than 3.
a>b ? a : b
// returns whichever is greater, a or 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;
return 0;
}
|
7
|
在这个例子中
a
是
2
、
b
是
7
,因此表达式计算
( a>b )
的结果不是
true
,因此问号后面的第一个值被忽略掉了,而第二个值
(
冒号后面的那个
)
也就是
b
被赋给了
c
。
逗号操作符
( , )
逗号
( , )
操作符用分割两个或多个表达式但只有一个表达式是想要的。当计算这个表达式集合的值的时候,最右面的表达式的值就是整个逗号表达式的值。
例如,下面的代码:
a = (b=3, b+2);
|
先把值
3
赋给
b
,在把
b+2
赋给
a
。因此,最后,变量
a
的值将是
5
而变量
b
的值为
3
。
位
(bit)
操作符
( &, |, ^, ~, <<, >> )
位操作符按位来修改保存在变量里的值。
操作符
|
等价的汇编指令
|
描述
|
&
|
AND
|
按位“与
(AND)
”
|
|
|
OR
|
按位“或
(OR)
”
|
^
|
XOR
|
按位“异或
(XOR)
”
|
~
|
NOT
|
按位取反
|
<<
|
SHL
|
左移
|
>>
|
SHR
|
右移
|
强制类型转换操作符
类型转换操作符允许你把一个数据转换成另一个类型。在
C++
有很多方法能够达成这个目的。最简单的方法,是从
C
语言继承来的,就是在想要转换的表达式前加上由小括号
( () )
包围起来的新的类型标识符:
int i;
float f = 3.14;
i = (int) f;
|
上面的代码把实数
3.14
转换成了整数值
(3)
,小数部分丢失了。这里的类型转换符是
(int)
。在
C++
中另外一种方法是使用函数符号:把想要转换到的类型写到要被转换的表达式的前面,再把要转换的表达式用小括号括起来:
i = int ( f );
|
两种类型转换的方法在
C++
中都是有效的。
.
sizeof()
这个操作符接受一个参数,这个参数可以是一个类型或一个变量本身,返回以字节计的类型或对象的大小:
a = sizeof (char);
|
这将把值
1
赋给
a
,因为
char
是单字节长的类型。
sizeof
的返回值是一个常量,因此它通常在程序执行前就已经确定了。
其他操作符
在这个指南的后面,我们会遇到一点其他的操作符,如指针操作符或面向对象编程
(object-oriented programming (OOP) )
的特殊操作符。
操作符的优先级
当写由几个操作数组成的复合表达式的时候,我们可能会对哪个操作数先被计算、哪个后被计算感到困惑。例如,在这个表达式中:
a = 5 + 7 % 2
|
我们或许会对他的意义感到疑惑:
a = 5 + (7 % 2)
// with a result of 6, or
a = (5 + 7) % 2
// with a result of 0
|
正确的答案是两个表达式中的第一个,拥有结果
6
。每个操作符的优先级顺序都是确定,并且不仅仅是算数操作符
(
那些来自数学的操作符
)
,而是在
C++
中出现的全部操作符。从最高优先级到最低,优先级顺序如下:
优先级
|
操作符
|
描述
|
结合性
|
1
|
::
|
域
|
左
->
右
|
2
|
() [] . -> ++ -- dynamic_cast static_cast reinterpret_cast const_cast typeid
|
后缀
|
左
->
右
|
3
|
++ -- ~ ! sizeof new delete
|
一元关系
(
前缀
)
|
右
->
左
|
* &
|
取址和引用
(
指针
)
| ||
+ -
|
一元符号操作符
| ||
4
|
(type)
|
类型转换
|
右
->
左
|
5
|
.* ->*
|
指向指针成员
|
左
->
右
t
|
6
|
* / %
|
乘除法
|
左
->
右
|
7
|
+ -
|
加减法
|
左
->
右
|
8
|
<< >>
|
位移
|
左
->
右
|
9
|
< > <= >=
|
关系
|
左
->
右
|
10
|
== !=
|
等价
|
左
->
右
|
11
|
&
|
按位
AND
|
左
->
右
|
12
|
^
|
按位
ie XOR
|
左
->
右
|
13
|
|
|
按位
OR
|
左
->
右
|
14
|
&&
|
逻辑
AND
|
左
->
右
|
15
|
||
|
逻辑
OR
|
左
->
右
|
16
|
?:
|
条件
|
右
->
左
|
17
|
= *= /= %= += -= >>= <<= &= ^= !=
|
赋值
|
右
->
左
|
18
|
,
|
逗号
|
左
->
右
|
结合性定义了当在一个表达式中有几个相同优先级的操作符的情况下操作符的计算优先顺序。
所有的这些优先级都能够通过使用小括号而变得确定或由于去掉了潜在的含义不明而变得更易读,就像在这个例子里:
a = 5 + 7 % 2;
|
可能写成这样更好:
a = 5 + (7 % 2);
|
或
a = (5 + 7) % 2;
|
取决于我们想要执行的操作。
因此如果你想写复杂的表达式而你又不完全确定优先级级别,那就总是加入小括号。它也会使代码更易读