More Selection & Iteration
We have covered the basics of selection, iteration and functions in C++, but here are several additional features you might to use:
- The switch statement which provides an efficient multi-way branch based on the concept of an integer selector.
- The conditional operator which allows you to turn a 4-line if-else statement into a single, compact, expression.
- The do-while, (or hasty) loop, for when you want to leap before you look.
Let's take these in order.
The switch Statement
The switch statement implicitly compares an integral expression (called the selector) to a series of constants (called the case labels). Here's the syntax:
switch (selector)
{
case constexpr1:
statement;
break;
case constexpr2:
statement;
break;
default:
statement;
}
Here's how the switch statement works:
- The switch selector is an integral expression.
- It is evaluated and compared against the case label constexpr1, then constexpr2, and so forth. As indicated, each label must be a constant integer expression.
- If a match is found for the selector, then control jumps to the first statement in the case block.
- When control reaches the break at the end of the clause, it jumps to the statement that follows the entire switch statement.
- The optional default specifies an action to be taken if none of the constants match the selector. If there is no default clause, the program simply continues on the line after the switch.
The constants in each case label statement must be of integral type. That means char and enumerated types are fine; string or double are not.
More on switch
Consider this code fragment inside a switch:
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
cout << "vowel";
break;
As you can see, break statements are not required at the end of each case. If the break is missing, the program continues executing the next clause after it finishes the selected one. We say the case falls-through.
This is useful as shown here where the output is printed for all of the lower-case vowels.
case ' ': case '\t': case '\n':
cout << "whitespace";
break;
If there is nothing in the body of the case, it may be more readable to format it like the whitespace block shown here.
If there is any code inside a case block that falls through, most compilers will issue a warning. If you intend to fall through, and you want to suppress the warning, add a comment like this, just before the second case:
// fall through
A Few More Rules
- Two case labels may not have the same value
- A label must precede a statement or another case label. It may not be alone.
- Variables may not be defined inside one case block and then used in another.
The Conditional Operator
The conditional or selection operator uses two symbols: ? and :, along with three different operands. It is also known as the ternary operator or tertiary operator for the number of operands. The general form is
(condition) ? true-result : false-result
The parentheses are not technically required, but programmers often include them to make things clearer. Here's how the conditional operator works:
- The condition is evaluated.
- If the condition is true, true-result is evaluated and used as the expression's value.
- If the condition is false, then false-result is used as the expression's.
Here are two examples:
int largest = (x > y) ? x : y;
cout << ((cats != 1) ? "cats" : "cat") << endl;
- Line 1 assigns the larger of x or y to the variable largest, without the need for a multi-line if statement.
- Line 2 prints "cat" if there is only one cat, and "cats" otherwise.
Note that when you use the conditional operator as part of an output statement, you must parenthesize the whole expression, since it has very low precedence.
A Hasty Loop
In addition to for and while, C++ has a loop that tests its condition after the loop body completes. The do-while loop always executes the statements inside its body at least once.
do
{
// statements
}
while (condition);
The body of the do-while loop appears between the keywords do (which precedes the loop body) and while. The body of the do-while loop can be a single statement, ending with a semicolon, or it can be a compound statement enclosed in braces.
In the do-while loop, the condition is followed by a semicolon, unlike the while loop, where following the condition with a semicolon leads to subtle, hard tofind bugs.
The do-while loop is often employed by beginning programmers because it seems more natural. If you find yourself in this situation, think twice. 99% of the time, a while loop or a for loop is a better choice than a do-while. In fact, except for salting your food... which should always be done before tasting, there are relatively few other situations where a test-at-the-bottom strategy is superior to "looking before you leap."
Confirmation Loops
When you make a withdrawal at your ATM, before your card is returned, the machine will ask you “Do you want to make another transaction?” This is a confirmation loop, and the do-while loop seems ideal for solving this problem.
However, there are still some things you need to watch out for. Considerthis code:
do
{
completeSomeTransaction();
cout << "Do you want another transaction? ";
string answer;
cin >> answer;
}
while (answer.front() == 'y');
While this looks reasonable (other than not providing for the empty string or an upper-case ‘Y’), it actually won’t compile. When you get to the loop condition, the string variable answer has gone out of scope.
To fix this, you have to move the initial declaration for answer before the do statement, which is not quite as clear. So, even in this natural use-case, the while loop is a little more efficient.