Booleans
The bool
type
If you recall from the Variables lesson,
one of basic types listed was bool
. This type represents a boolean, which is a
single true/false value.
The Boolean Expressions
we learned about early in this Conditions lesson create a boolean value when evaluated.
So, we can make variables that are the results of such boolean expressions, and then
further use these bool
variables in the conditions of if statements.
C++ provides two built-in bool
constants - true
and false
. You can use these wherever
a bool
or boolean expression is expected. For example:
bool var1 = true;
bool var2 = false;
There are more interesting things we can do with bool
variables, too.
Any boolean expression is valid to assign here. Combining this with
if statements can make for shorter and more readable code in some cases.
std::string name;
std::cout << "Enter your first name: ";
std::cin >> name;
// User is lucky if their name has more than 5 characters
bool is_lucky = name.size() > 5;
// Try changing these values yourself and see what happens!
bool is_tuesday = true;
bool is_cloudy = false;
std::string weather = "sunny";
if (not is_tuesday and is_cloudy) {
weather = "raining";
} else if (is_tuesday) {
if (is_cloudy) {
weather = "overcast";
} else if (not is_lucky) {
weather = "downpouring";
}
}
std::cout << "It is currently " << weather << " in your location!";
The logical operators previously introduced can also be used to create new boolean variables.
bool is_precipitating = weather == "raining" or weather == "downpouring";
bool is_rainbow_made = is_precipitating and not is_cloudy;
bool is_boring_day = not is_rainbow_made;
Input/Output with bool
If you did any self-driven exploration with this new bool
type, you may have noticed a peculiar thing...
Printing out a bool
does not display a true
or false
in the terminal. Instead, it prints out a 1
or a 0
.
This is simply a default behavior in C++ that is related to the next section.
You can easily change this behavior by changing one of std::cout
's settings.
Simply "print" out the std::boolalhpa
built-in constant, and it will make all future boolean operations on std::cout
print out true
/false
instead of 1
/0
.
Make sure you #include <iomanip>
to use std::boolalpha
.
std::cout << true << " " << false << "\n";
std::cout << std::boolalpha;
std::cout << true << " " << false << "\n";
1 0
true false
Conversely, std::cin
by default will only accept a 0
or a 1
when inputting into a bool
variable.
This behavior can also be changed by "inputting" into the std::boolalpha
flag.
In the example below, the user will first input 0
, which represents false
.
Then, they will input true
once the std::boolalpha
setting was applied.
bool var;
std::cout << "Integral form: ";
std::cin >> var;
std::cin >> std::boolalpha;
std::cout << "Alphanumeric form: ";
std::cin >> var;
Integral form: 1
Alphanumeric form: true
As an exercise, try modifying the weather example from above to accept user input, using
the std::boolalpha
modifier you just learned.
The name "boolalpha" comes from a portmanteau of boolean and alphanumeric.
int
↔bool
conversions
C++ has another rather annoying behavior where booleans and integers can implicitly convert between each other.
A boolean value of false
is equivalent to an integer value of 0
, and true
is equivalent to 1
.
Conversely, an integral value of 0
is equivalent to a boolean value of false
,
and any non-zero integer is equivalent to true
.
int x = true; // x is 1
int y = false; // y is 0
bool a = 1; // a is true
bool b = 25; // b is true
bool c = -194; // c is true
bool d = 0; // d is false
While this behavior may seem neat, it can unexpectedly crop up in many places where they are not wanted.
For this reason, if you want to intentionally trigger an int
↔bool
conversion, then you should cast
the value.
int x = static_cast<int>(true); // Modern-style cast
int y = (int) false; // C-style cast
bool a = static_cast<bool>(1);
bool b = (bool) 0;
There are two primary ways to perform a cast like this in C++ - a "static cast" and a "c-style cast".
You will learn the differences between these in the Intermediate course. For now just know that,
in the case of int
↔bool
conversions, both of the options are equivalent.
However, the static_cast
method is generally preferred for Modern C++.
Unintended Conversions
These conversions can cause issues where you least expect them to. One example is in the compound boolean expressions you learned about earlier. Normally, if you want to combine multiple boolean expressions together, you use the logical operators like so:
if (x > 10 && x < 25) { ... }
You may be tempted to rewrite the condition as 10 < x < 25
.
This will result in incorrect behavior, as this expression will always evaluate to true
.
This is because there is secretly an implicit bool
🡢int
conversion occurring.
This expression gets interpreted as (10 < x) < 25
.
Let's see how this causes this condition to always evaluate to true
by using
the operator precedence table:
10 < x < 25 // Initial expression
10 < 15 < 25 // Substitute x
(10 < 15) < 25 // Operator precedence
(true) < 25 // Evaluate subexpression
1 < 25 // bool🡢int conversion
true // Evaluate subexpression
10 < x < 25 // Initial expression
10 < 7 < 25 // Substitute x
(10 < 7) < 25 // Operator precedence
(false) < 25 // Evaluate subexpression
0 < 25 // bool🡢int conversion
true // Evaluate subexpression
This same issue can occur in other similar scenarios, as well.
For example, when checking if a single variable is one of many possibilities,
the correct way would be x == 5 || x == 10 || x == 15
.
The tempting option of x == 5 || 10 || 15
will not work for a similar reason to the above.
It will always be true. Let's see why:
x == 5 || 10 || 15 // Initial expression
5 == 5 || 10 || 15 // Substitute x
((5 == 5) || 10) || 15 // Operator precedence
((true) || 10) || 15 // Evaluate subexpression
(true || true) || 15 // int🡢bool conversion
true || 15 // Evaluate subexpression
true || true // int🡢bool conversion
true // Evaluate subexpression
x == 5 || 10 || 15 // Initial expression
7 == 5 || 10 || 15 // Substitute x
((7 == 5) || 10) || 15 // Operator precedence
((false) || 10) || 15 // Evaluate subexpression
(false || true) || 15 // int🡢bool conversion
true || 15 // Evaluate subexpression
true || true // int🡢bool conversion
true // Evaluate subexpression
Conclusion
In summary, we learned about:
- How to break down conditional cases in our code into if statements
- How to form a logical expression out of boolean operations
- How to combine multiple conditions into a mutually exclusive group
- How to nest if statements inside of each other
- How to reduce reptition by applying the DRY Principle
- How to use boolean variables to improve our code
This was a long journey, but the skills you have picked up here in this lesson are very fundamental to the road ahead. Read over the concepts presented in this lesson multiple times, as the basics of logic and conditions are a very important skill to have.