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, because the precedence of == is higher than the precedence of &&. If necessary, the simple condition to the right of the && operator evaluates next, because the precedence of >= is higher than the precedence of &&. As we will 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
gender == 1 && age >= 65
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.
expression1 |
expression2 |
expression1 && 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 (||).
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, the programmer 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 (!).
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. However, we use stream manipulator boolalpha in line 11 to specify that the value of each bool expression should be displayed either as 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 1115 produce the truth table for &&. Lines 1822 produce the truth table for ||. Lines 2527 produce the truth table for !.
Figure 5.18. Logical operators.
(This item is displayed on pages 214 - 215 in the print version)
1 // Fig. 5.18: fig05_18.cpp 2 // Logical operators. 3 #include 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 << " false && false: " << ( false && false ) 13 << " false && true: " << ( false && true ) 14 << " true && false: " << ( true && false ) 15 << " true && true: " << ( true && true ) << " "; 16 17 // create truth table for || (logical OR) operator 18 cout << "Logical OR (||)" 19 << " false || false: " << ( false || false ) 20 << " false || true: " << ( false || true ) 21 << " true || false: " << ( true || false ) 22 << " true || true: " << ( true || true ) << " "; 23 24 // create truth table for ! (logical negation) operator 25 cout << "Logical NOT (!)" 26 << " !false: " << ( !false ) 27 << " !true: " << ( !true ) << endl; 28 return 0; // indicate successful termination 29 } // end main
|
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.
Operators |
Associativity |
Type |
|||||
---|---|---|---|---|---|---|---|
() |
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 |