MC++提供了一些逻辑和条件运算符,可以使用它们将一些简单条件组合成复杂的条件。这种运算符有&& (条件与)、&(逻辑与)、| |(条件或)、|(逻辑或)、^(逻辑异或,或者是逻辑XOR),以及!(逻辑非)。在本节中,我们将举例说明如何使用这些运算符。
| 常见的编程错误3.10 |
在运算符&&和||的两个字符中间插入空格符是一个语法错误。 |
在程序中,如果我们希望在两个条件都满足时才选择一条相应的执行路径,这时就可以使用条件&&运算符,如下所示:
if (gender == 1 && age >= 65)
++seniorFemales
上面的if语句中包含两个简单条件。条件gender==1检查是否是女性;条件age>=65检查是否是年长者。因为==和>=运算符的优先级都比&&要高,所以程序首先计算两个简单条件的值。If语句将考虑组合条件
gender == 1 && age >= 65
只有在这两个简单条件都为真时,这个组合条件才可满足。如果这个组合条件为真,if结构体内的语句就将seniorFemales的值增加1。若两个简单条件中的任意一个为假,则程序跳过递增的步骤,并且继续执行if结构后面的语句。
下面分析||(条件或)运算符。如果我们希望在两个条件中的任意一个满足(或者两个条件都满足)时选择一条相应的执行路径,这时就可以使用条件||运算符,如下所示:
if (semesterAverage >= 90 || finalExam >= 90)
Console::WriteLine(S"Student grade is A");
上面的if语句同样包含两个简单条件。条件semesterAverage>=90表示这名学生在该门课程中是否应该根据整个学期的总体表现而得“A”。条件finalExam>=90表示这名学生在该门课程中是否应该根据期末考试取得的高分而得“A”。if语句考虑组合条件
semesterAverage >= 90 || finalExam >= 90
如果任意一个简单条件为真,或者两个都为真,这个学生就能获得“A”。也就是说,除非这两个条件都为假,否则将显示消息“Student grade is A”。
&&运算符的优先级比||要高。两个运算符的结合性都是从左至右。包含&&(或||)运算符的表达式的求值在已知“假”(或“真”)时就结束。因此,如果已知gender的值不等于1,表达式
gender == 1 && age >= 65
的求值过程将立即停止(即如果有一个条件为假,则整个表达式也为假)。而如果gender等于1,则计算过程将继续(即如果条件age>=65为真,则整个表达式仍会为真)。条件与和条件或表达式的这种性能特性称为“快速求值”。
| 性能技巧3.3 |
在使用运算符&&的表达式中,如果每个简单条件都是互相独立的,则可以将值最可能为假的简单条件置于最左边。而在使用运算符//的表达式中, 将值最可能为真的简单条件置于最左边。这种应用“快速求值”的方法可减少程序的运行时间。 |
在程序中因为一个条件取值而可能引起错误的情形下,使用“快速求值”是非常有用的。例如,如果grades的值不大于0,则对下面表达式的计算会立即停止;
grades > 0 &&(total / grade > 60)
只有当grades大于0时才计算后面表达式的值。注意如果我们省略掉第一个条件(grades>0),并且grades的值为0,则第二个条件(total/grades>60)将会以0作为除数,这将引起程序的“异常”错误,从而终止程序的执行。在第8章“异常处理”中将详细讨论异常。
逻辑与(&)运算符和逻辑或(|)运算符分别类似于条件与(&&)运算符和条件或(||)运算符。然而逻辑运算符需要计算它的两个操作数的值(即不存在“快速求值”)。因此,不论gender的值是否为1,表达式
gender == 1 & age >= 65
都会对age>=65求值。这个特点在逻辑与运算符或逻辑或运算符的右操作数中含有必须执行的附带功能时是非常有用的,例如修改一个变量的值。例如,不论整个表达式的值是真还是假,表达式
birthday == true & Console::Writeline(age)
都会显示前述表达式中变量age的值。同样的,如果要使右操作数中的条件是某个数学运算的结果,并且要让这次数学运算在任何情形下都必须执行,这时就可以使用“|”运算符。
| 测试和调试技巧3.2 |
避免使用在条件中带有附带功能的表达式。附带功能看起来是很灵活,但它们常会引发一些隐蔽性的错误,并且使阅读和维护代码更为困难。 |
返回值也是逻辑运算符(&和|)同条件运算符(&&和||)的区别之一。条件运算符返回boolean类型的值(true或者false),而逻辑运算符是按位运算符,它返回整型值(0或者1)。在附录I“位操作”中将讨论按位运算符。
包含逻辑异或运算符(^)(有时写为逻辑XOR运算符)的条件值只有在以下情况中才为真:它的两个操作数中一个值为真,而另一个值为假。如果两个操作数的值都为真或都为假,则这个条件为假。对该运算符的两个操作数都需要求值(即不存在“快速求值”的方式)。
MC++提供了!(逻辑非)运算符,程序员可使用该运算符来“翻转”条件所表达的意义。同运算符&&、&、||、|和^需要两个操作数(因此为二元运算符)不同,逻辑非运算符只需要一个操作数作为条件(因此它是一元运算符)。逻辑非运算符位于条件之前,如果这个初始条件(没有逻辑非运算符时)为假,则选择一条路径执行。例如,下面的if结构:
if (!finished)
Console::Writeline("Not finished. ");
只有在finishd为假时才会执行if结构的主体。
通过在控制台窗口中显示它们的真值表,图3-13中的控制台应用程序说明了所有条件和逻辑运算符的使用。
1 // Fig. 3-13: LogicalOperators.cpp
2 // Demonstrating the logical operators.
3
4 #using <mscorlib.dll>
5
6 using namespace System;
7
8 int main()
9 {
10
11 // testing conditional AND operator (&&)
12 Console::WriteLine( String::Concat(
13 S"Conditional AND (&&)",
14 S"/nfalse && false: ", ( false && false ).ToString(),
15 S"/nfalse && true: ", ( false && true ).ToString(),
16 S"/ntrue && false: ", ( true && false ).ToString(),
17 S"/ntrue && true: ", ( true && true ).ToString() ) );
图3-13 条件和逻辑运算符
18
19 // testing conditional OR operator (||)
20 Console::WriteLine( String::Concat(
21 S"/n/nConditional OR (||)",
22 S"/nfalse || false: ", ( false || false ).ToString(),
23 S"/nfalse || true: ", ( false || true ).ToString(),
24 S"/ntrue || false: ", ( true || false ).ToString(),
25 S"/ntrue || true: ", ( true || true ).ToString() ) );
26
27 // testing logical AND operator (&)
28 Console::WriteLine( String::Concat(
29 S"/n/nLogical AND (&)",
30 S"/nfalse & false: ",
31 ( false & false ) ? S"True" : S"False",
32 S"/nfalse & true: ",
33 ( false & true ) ? S"True" : S"False",
34 S"/ntrue & false: ",
35 ( true & false ) ? S"True" : S"False",
36 S"/ntrue & true: ",
37 ( true & true ) ? S"True" : S"False" ) );
38
39 // testing logical OR operator (|)
40 Console::WriteLine( String::Concat(
41 S"/n/nLogical OR (|)",
42 S"/nfalse | false: ",
43 ( false | false ) ? S"True" : S"False",
44 S"/nfalse | true: ",
45 ( false | true ) ? S"True" : S"False",
46 S"/ntrue | false: ",
47 ( true | false ) ? S"True" : S"False",
48 S"/ntrue | true: ",
49 ( true | true ) ? S"True" : S"False" ) );
50
51 // testing logical exclusive OR operator (^)
52 Console::WriteLine( String::Concat(
53 S"/n/nLogical exclusive OR (^)",
54 S"/nfalse ^ false: ",
55 ( false ^ false ) ? S"True" : S"False",
56 S"/nfalse ^ true: ",
57 ( false ^ true ) ? S"True" : S"False",
58 S"/ntrue ^ false: ",
59 ( true ^ false ) ? S"True" : S"False",
60 S"/ntrue ^ true: ",
61 ( true ^ true ) ? S"True" : S"False" ) );
62
63 // testing logical NOT operator (!)
图3-13 续
64 Console::WriteLine( String::Concat(
65 S"/n/nLogical NOT (!)",
66 S"/n!false: ", ( !false ).ToString(),
67 S"/n!true: ", ( !true ).ToString() ) );
68
69 return 0;
70 } // end main
Conditional AND (&&)
false && false: False
false && true: False
true && false: False
true && true: True
Conditional OR (||)
false || false: False
false || true: True
true || false: True
true || true: True
Logical AND (&)
false & false: False
false & true: False
true & false: False
true & true: True
Logical OR (|)
false | false: False
false | true: True
true | false: True
true | true: True
Logical exclusive OR (^)
false ^ false: False
false ^ true: True
true ^ false: True
true ^ true: False
Logical NOT (!)
!false: True
!true: False
图3-13 续
第12~17行
演示了&&运算符;第28~37行演示的是&运算符,其余各行则分别演示||、|、^和!运算符。第12-25行通过应用ToString方法以字符串形式分别输出表达式的值。对于&&、||和!运算符的情形,表达式值的字符串形式是“False”或者“True”。而对&、|、和^运算符的情形,表达式的值是“0”或“1”。但在第28~61行中,我们通过三元条件运算符?:使输出为“False”(而非“0”)和“True”(而不是“1”)。这仅仅是为了使整个程序的输出协调一致。
图3-14列出了先前介绍的MC++运算符的优先级与结合性。这些运算符从上至下按优先级递减的顺序排列。
运 算 符 | 结 合 性 | 类 型 |
() | 从左向右 | 圆括号 |
++ -- | 从左向右 | 一元后缀 |
++ -- + - ! (type) | 从右向左 | 一元前缀 |
* / % | 从左向右 | 乘法 |
+ - | 从左向右 | 加法 |
< <= > >= | 从左向右 | 关系 |
== != | 从左向右 | 等值 |
& | 从左向右 | 逻辑与 |
^ | 从左向右 | 逻辑异或(XOR) |
| | 从左向右 | 逻辑或 |
&& | 从左向右 | 条件与 |
|| | 从左向右 | 条件或 |
?: | 从右向左 | 条件 |
= += -= *= /= %= | 从右向左 | 赋值 |
图3-14 已讨论的运算符的优先级和结合性