- 4.1 Introduction
- 4.2 Essentials of Counter-Controlled Iteration
- 4.3 for Iteration Statement
- 4.4 Examples Using the for Statement
- 4.5 Application: Summing Even Integers
- 4.6 Application: Compound-Interest Calculations
- 4.7 do... while Iteration Statement
- 4.8 switch Multiple-Selection Statement
- 4.9 C++17 Selection Statements with Initializers
- 4.10 break and continue Statements
- 4.11 Logical Operators
- 4.12 Confusing the Equality (==) and Assignment (=) Operators
- 4.13 Objects-Natural Case Study: Using the miniz-cpp Library to Write and Read ZIP files
- 4.14 C++20 Text Formatting with Field Widths and Precisions
- 4.15 Wrap-Up
4.11 Logical Operators
The conditions in if, if…else, while, do…while and for statements determine how to continue a program’s flow of control. So far, we’ve studied only simple conditions, such as count <= 10, number != sentinelValue and total > 1000. Simple conditions are expressed with the relational operators >, <, >= and <= and the equality operators == and !=. Each tests one condition. Sometimes control statements require more complex conditions to determine a program’s flow of control. C++’s logical operators enable you to combine simple conditions. The logical operators are && (logical AND), || (logical OR) and ! (logical negation).
4.11.1 Logical AND (&&) Operator
Suppose we wish to ensure at some point in a program 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 == FEMALE && age >= 65) { ++seniorFemales; }
Assume FEMALE is a constant variable. This if statement contains two simple conditions. The condition gender == FEMALE determines whether a person is female. The condition age >= 65 might be evaluated to determine whether a person is a senior citizen. The if statement considers the combined condition
gender == FEMALE && age >= 65
which is true if and only if both simple conditions are true. In this case, the if statement’s body increments seniorFemales by 1. If either or both of the simple conditions are false, the program skips the increment. Some programmers find that the preceding combined condition is more readable when redundant parentheses are added, as in
(gender == FEMALE) && (age >= 65)
The following truth table summarizes the && operator, showing all four possible combinations of the bool values false and true for expression1 and expression2. C++ evaluates to zero (false) or nonzero (true) all expressions that include relational operators, equality operators or logical operators:
expression1 |
expression2 |
expression1 |
&& expression2 |
---|---|---|---|
false |
false |
false |
|
false |
true |
false |
|
true |
false |
false |
|
true |
true |
true |
|
4.11.2 Logical OR (||) Operator
Now suppose we wish to ensure that either or both of two conditions are true before we choose a certain path of execution. In this case, we use the || (logical OR) operator, as in the following program segment:
if ((semesterAverage >= 90) || (finalExam >= 90)) { cout << "Student grade is A\n"; }
This statement also contains two simple conditions. The condition semesterAverage >= 90 determines whether the student deserves an A in the course for a solid performance throughout the semester. The condition finalExam >= 90 determines whether the student deserves an A in the course for 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. The only time the message "Student grade is A" is not printed is when both of the simple conditions are false. The following is the truth table for the operator logical OR (||):
expression1 |
expression2 |
expression1 |
|| expression2 |
---|---|---|---|
false |
false |
false |
|
false |
true |
true |
|
true |
false |
true |
|
true |
true |
true |
|
Operator && has higher precedence than operator ||.5 Both operators group left-to-right.
4.11.3 Short-Circuit Evaluation
The parts of an expression containing && or || operators are evaluated only until it’s known whether the condition is true or false. Thus, evaluation of the expression
(gender == FEMALE) && (age >= 65)
stops immediately if gender is not equal to FEMALE (i.e., the entire expression is false) and continues if gender is equal to FEMALE (i.e., the entire expression could still be true if the condition age >= 65 is true). This feature of logical AND and logical OR expressions is called short-circuit evaluation.
In expressions using operator &&, a condition—we’ll call this the dependent condition—may require another condition to be true for the evaluation of the dependent condition to be meaningful. In this case, the dependent condition should be placed after the && operator to prevent errors. Consider the expression (i != 0) && (10 / i == 2). The dependent condition (10 / i == 2) must appear after the && operator to prevent the possibility of division by zero.
4.11.4 Logical Negation (!) Operator
The ! (logical negation, also called logical NOT or logical complement) operator “reverses” the meaning of a condition. Unlike the logical operators && and ||, which are binary operators that combine two conditions, the logical negation operator is a unary operator that has only one condition as an operand. To execute code only when a condition is false, place the logical negation operator before the original condition, as in the program segment
if (!(grade == sentinelValue)) { cout << "The next grade is " << grade << "\n"; }
which executes the body statement only if grade is not equal to sentinelValue. The parentheses around the condition grade == sentinelValue are needed because the logical negation operator has higher precedence than the equality operator.
In most cases, you can avoid using logical negation by expressing the condition differently with an appropriate relational or equality operator. For example, the previous statement may also be written in a more readable manner as
if (grade != sentinelValue) { cout << "The next grade is " << grade << "\n"; }
This flexibility can help you express a condition more conveniently. The following is the truth table for the logical negation operator:
expression |
!expression |
---|---|
false |
true |
true |
false |
4.11.5 Example: Producing Logical-Operator Truth Tables
Figure 4.10 uses logical operators to produce the truth tables discussed in this section. The output shows each expression that’s 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, but the format function displays the word “true” or the word “false.” Lines 10–14, 17–21 and 24–26 produce the truth tables for &&, || and !, respectively.
1 // fig04_10.cpp 2 // Logical operators. 3 #include <iostream> 4 #include <fmt/format.h> // in C++20, this will be #include <format> 5 using namespace std; 6 using namespace fmt; // not needed in C++20 7 8 int main() { 9 // create truth table for && (logical AND) operator 10 cout << "Logical AND (&&)\n" 11 << format("false && false: {}\n", false && false) 12 << format("false && true: {}\n", false && true) 13 << format("true && false: {}\n", true && false) 14 << format("true && true: {}\n\n", true && true); 15 16 // create truth table for || (logical OR) operator 17 cout << "Logical OR (||)\n" 18 << format("false || false: {}\n", false || false) 19 << format("false || true: {}\n", false || true) 20 << format("true || false: {}\n", true || false) 21 << format("true || true: {}\n\n", true || true); 22 23 // create truth table for ! (logical negation) operator 24 cout << "Logical negation (!)\n" 25 << format("!false: {}\n", !false) 26 << format("!true: {}\n", !true); 27 }
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 negation (!) !false: true !true: false
Fig. 4.10 Logical operators.
Precedence and Grouping of the Operators Presented So Far
The following table shows the precedence and grouping of the C++ operators introduced so far—from top to bottom in decreasing order of precedence:
Operators |
Grouping |
---|---|
++ -- static_cast<type>() |
left to right |
++ -- + - ! |
right to left |
* / % |
left to right |
+ - |
left to right |
<< >> |
left to right |
< <= > >= |
left to right |
== != |
left to right |
&& |
left to right |
|| |
left to right |
?: |
right to left |
= += -= *= /= %= |
right to left |
, |
left to right |