5.8. Logical Operators
So far we have studied only simple conditions, such as counter <= 10, total > 1000 and number !=
sentinelValue. We expressed these conditions in
terms of the relational operators >, <, >=
and <=, and the equality operators
== and !=. Each decision tested
precisely one condition. To test multiple conditions while making a decision, we
performed these tests in separate statements or in nested if or
if...else statements.
C++ provides logical
operators that are used to form more
complex conditions by combining simple conditions. The logical operators are
&& (logical AND), || (logical OR) and !
(logical NOT, also called logical negation).
Logical AND (&&) Operator
Suppose that we wish to ensure
that two conditions are both true before we choose a certain path of execution. In this
case, we can use the &&
(logical AND) operator, as follows:
if ( gender == 1 && age >= 65 )
seniorFemales++;
This if statement contains two simple conditions. The
condition gender == 1 is used here to
determine whether a person is a female. The condition age
>= 65 determines whether a person is a senior
citizen. The simple condition to the left of the && operator
evaluates first. If necessary, the simple condition to the right of the
&& operator evaluates next. As we'll
discuss shortly, the right side of a logical AND expression is evaluated only if
the left side is true. The if
statement then considers the combined condition
This condition is true if and only if both of the
simple conditions are true. Finally, if this combined condition is
indeed true, the statement in the if statement's body increments the
count of seniorFemales. If either of the simple conditions is
false (or both are), then the program skips
the incrementing and proceeds to the statement following the if. The preceding combined condition can be made more
readable by adding redundant parentheses:
( gender == 1 ) && ( age >= 65 )
Common Programming Error 5.13
|
Although 3 < x < 7 is a mathematically correct condition, it does not evaluate
as you might expect in C++. Use ( 3 < x && x < 7 ) to get
the proper evaluation in C++. |
Figure
5.15 summarizes the && operator. The table shows all four
possible combinations of false and true values for expression1 and expression2. Such tables are often called truth tables. C++ evaluates to false or
true all expressions that include relational operators, equality
operators and/or logical operators.
Fig. 5.15. && (logical AND) operator
truth table.
| expression1 |
expression2 |
expression| &&
expression2 |
| false |
false |
false |
| false |
true |
false |
| true |
false |
false |
| true |
true |
true |
Logical OR (||) Operator
Now let us consider the || (logical OR) operator.
Suppose we wish to ensure at some point in a program that either or both of two conditions are
true before we choose a certain path of
execution. In this case, we use the ||
operator, as in the following program segment:
if ( ( semesterAverage >= 90 ) || ( finalExam >= 90 ) )
cout << "Student grade is A" << endl;
This preceding condition also
contains two simple conditions. The simple condition semesterAverage >=
90 evaluates to determine whether the student
deserves an "A" in the course because of a solid performance throughout the
semester. The simple condition finalExam >= 90 evaluates to determine whether the student deserves
an "A" in the course because of an outstanding performance on the final exam.
The if statement then considers the combined condition
( semesterAverage >= 90 ) || ( finalExam >= 90 )
and awards the student an "A" if either
or both of the simple conditions are true. Note that the message
"Student grade is A" prints unless both of the
simple conditions are false. Figure 5.16 is a truth table for the
logical OR operator (||).
Fig. 5.16. || (logical OR) operator truth
table.
| expression1 |
expression2 |
expression1 ||
expression2 |
| false |
false |
false |
| false |
true |
true |
| true |
false |
true |
| true |
true |
true |
The && operator has a higher precedence than
the || operator. Both operators associate from left to right. An
expression containing && or || operators evaluates only until the truth or falsehood
of the expression is known. Thus, evaluation of the expression
( gender == 1 ) && ( age >= 65 )
stops immediately if
gender is not equal to 1 (i.e.,
the entire expression is false) and continues if
gender is equal to 1 (i.e., the
entire expression could still be true if the condition age
>= 65 is true). This performance feature
for the evaluation of logical AND and logical OR expressions is called short-circuit evaluation.
Performance Tip 5.6
|
In expressions using operator
&&, if the separate conditions are
independent of one another, make the condition most likely to be
false the leftmost condition. In
expressions using operator ||, make the condition most likely to be
true the leftmost condition. This use of short-circuit evaluation can
reduce a program's execution
time. |
Logical Negation (!) Operator
C++ provides the ! (logical
NOT, also called logical negation) operator to enable a programmer to "reverse" the meaning
of a condition. Unlike the && and || binary operators, which combine two conditions, the
unary logical negation operator has only a single condition as an operand. The
unary logical negation operator is placed before a condition when we are
interested in choosing a path of execution if the original condition (without
the logical negation operator) is false,
such as in the following program segment:
if ( !( grade == sentinelValue ) )
cout << "The next grade is " << grade << endl;
The parentheses around the condition
grade == sentinelValue are needed because the
logical negation operator has a higher precedence than the equality
operator.
In most cases, you can avoid using
logical negation by expressing the condition with an appropriate relational or
equality operator. For example, the preceding if statement also can be
written as follows:
if ( grade != sentinelValue )
cout << "The next grade is " << grade << endl;
This flexibility often can help a
programmer express a condition in a more "natural" or convenient manner. Figure 5.17 is a truth table for the logical negation operator
(!).
Fig. 5.17. ! (logical negation) operator truth
table.
| expression |
!expression |
| false |
true |
| true |
false |
Logical Operators Example
Figure
5.18 demonstrates the logical operators by
producing their truth tables. The output shows each expression that is evaluated
and its bool result. By default, bool
values true and false are displayed by cout and the stream insertion operator as 1
and 0, respectively. We use stream
manipulator boolalpha (a sticky
manipulator) in line 11 to specify that the value of each bool expression should be displayed as either the word
"true" or the word "false." For example, the result of the expression false
&& false in line 12 is false, so the
second line of output includes the word "false." Lines 11–15 produce the truth
table for &&. Lines 18–22 produce the truth table for
||. Lines 25–27 produce the truth table for !.
Fig. 5.18. Logical operators.
1 // Fig. 5.18: fig05_18.cpp
2 // Logical operators.
3 #include <iostream>
4 using std::cout;
5 using std::endl;
6 using std::boolalpha; // causes bool values to print as "true" or "false"
7
8 int main()
9 {
10 // create truth table for && (logical AND) operator
11 cout << boolalpha << "Logical AND (&&)"
12 << "\nfalse && false: " << ( false && false )
13 << "\nfalse && true: " << ( false && true )
14 << "\ntrue && false: " << ( true && false )
15 << "\ntrue && true: " << ( true && true ) << "\n\n";
16
17 // create truth table for || (logical OR) operator
18 cout << "Logical OR (||)"
19 << "\nfalse || false: " << ( false || false )
20 << "\nfalse || true: " << ( false || true )
21 << "\ntrue || false: " << ( true || false )
22 << "\ntrue || true: " << ( true || true ) << "\n\n";
23
24 // create truth table for ! (logical negation) operator
25 cout << "Logical NOT (!)"
26 << "\n!false: " << ( !false )
27 << "\n!true: " << ( !true ) << endl;
28 return 0; // indicate successful termination
29 } // end main
|
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 NOT (!)
!false: true
!true: false
|
Summary of Operator Precedence and
Associativity
Figure 5.19 adds the logical operators to the operator precedence
and associativity chart. The operators are shown from top to bottom, in
decreasing order of precedence.
Fig. 5.19. Operator precedence and
associativity.
| Operators |
|
|
|
|
|
Associativity |
Type |
| :: |
|
|
|
|
|
left to right |
scope resolution |
| () |
|
|
|
|
|
left to right |
parentheses |
| ++ |
-- |
static_cast< type >() |
left to right |
unary (postfix) |
| ++ |
-- |
+ |
- |
! |
|
right to left |
unary (prefix) |
| * |
/ |
% |
|
|
|
left to right |
multiplicative |
| + |
- |
|
|
|
|
left to right |
additive |
| << |
>> |
|
|
|
|
left to right |
insertion/extraction |
| < |
<= |
> |
>= |
|
|
left to right |
relational |
| == |
!= |
|
|
|
|
left to right |
equality |
| && |
|
|
|
|
|
left to right |
logical AND |
| || |
|
|
|
|
|
left to right |
logical OR |
| ?: |
|
|
|
|
|
right to left |
conditional |
| = |
+= |
-= |
*= |
/= |
%= |
right to left |
assignment |
| , |
|
|
|
|
|
left to right |
comma |