You already know how to shape a program's flow using if-else statements. However, in some cases, you will be working with a limited set of discrete options. For example, when you have 5-10 options to choose from, you would need to write complex if/else chains for each case. Fortunately, you can avoid this approach and make your code both readable and maintainable. Let's explore an alternative way to handle multiple choices.
Background
Let's explore a common scenario: a game menu. Imagine you want to present players with several options that they can select from:
#include <iostream>
int main() {
int choice;
std::cout << "Game Menu\n";
std::cout << "1. New Game\n";
std::cout << "2. Continue Game\n";
std::cout << "3. Settings\n";
std::cout << "4. Quit\n";
std::cout << "Choose an option: ";
std::cin >> choice;
if (choice == 1) {
std::cout << "Starting a new game...\n";
} else if (choice == 2) {
std::cout << "Continuing the game...\n";
} else if (choice == 3) {
std::cout << "Opening settings...\n";
} else if (choice == 4) {
std::cout << "Exiting the game...\n";
} else {
std::cout << "Invalid choice. Please try again.\n";
}
return 0;
}While this code works, it can become difficult to understand when dealing with many conditional branches, especially for other developers (or yourself when reviewing the code later). This is where the switch statement becomes particularly useful.
Introducing the switch statement
The switch statement provides a clear way to choose between multiple cases based on a single variable's value. Let's look at the same game menu example using the switch statement:
#include <iostream>
int main() {
int choice;
std::cout << "Game Menu\n";
std::cout << "1. New Game\n";
std::cout << "2. Continue Game\n";
std::cout << "3. Settings\n";
std::cout << "4. Quit\n";
std::cout << "Choose an option: ";
std::cin >> choice;
switch (choice) {
case 1:
std::cout << "Starting a new game..." << std::endl;
break;
case 2:
std::cout << "Continuing the game..." << std::endl;
break;
case 3:
std::cout << "Opening settings..." << std::endl;
break;
case 4:
std::cout << "Exiting the game..." << std::endl;
break;
default:
std::cout << "Invalid choice. Please try again.\n";
break;
}
return 0;
}Notice how this code is cleaner and more structured than a long if/else if chain. Each option is clear. Even if you're new to switch, case, and break, you can probably already understand what they do.
Dissecting the switch statement
Now, let's take a closer look at the switch statement and its components:
switch (choice) { // The 'switch' keyword initiates the statement
case 1: // 'case' labels define specific values
std::cout << "Starting a new game..." << std::endl;
break; // 'break' exits the switch statement
case 2:
std::cout << "Continuing the game..." << std::endl;
break;
case 3:
std::cout << "Opening settings..." << std::endl;
break;
case 4:
std::cout << "Exiting the game..." << std::endl;
break;
default: // 'default' handles unmatched values
std::cout << "Invalid choice. Please try again.\n";
break;
}switch (expression): Theswitchkeyword introduces the statement, followed by an expression in parentheses that will be evaluated. This expression is typically an integral type (likeint,bool,char), and can include others likeenumand certainclasstypes (those that can be implicitly converted to integral orenumtypes).case value:: Thecasekeyword defines a specific value to match against theswitchexpression. When theexpression's value equalsvalue, the code block for that case will run.break;: This statement is optional, but essential withinswitch. When the program reachesbreak, it immediately exits the entireswitchstatement, preventing the execution of othercaselabels.default:: Thedefaultkeyword is optional. When included, its code block runs if nocasevalues match theswitchexpression. It serves as a catch-all for unexpected values.
Why break is your friend
You may have noticed that the break statement is optional. This is where switch statements can become tricky if you're not careful. When you omit break after a case, the execution will "fall through" to the next case label, executing its code. This continues until one of the following termination conditions occurs:
The end of the switch block is reached.
A
returnstatement is encounteredA
breakstatement is executed.
If none of these termination conditions are met, the program will execute all the cases following the matched case. Here's an example:
#include <iostream>
int main() {
int option = 2;
switch (option) {
case 1:
std::cout << "This option is not suitable, we will not print.\n";
case 2:
std::cout << "Oh we'll print it.\n";
case 3:
std::cout << "And we'll print it too...\n";
case 4:
std::cout << "And this too??? YEP!\n";
case 5:
std::cout << "And this 8)\n";
default:
std::cout << "And this\n";
}
return 0;
}As a result of executing the code, you get the following:
Oh we'll print it.
And we'll print it too...
And this too??? YEP!
And this 8)
And thisThis behavior is likely not what you intended! Without break statements, the program executes code for case 3, case 4, case 5, and default, even though option matches only case 2. Remember to include break statements at the end of each case block unless you specifically want fall-through behavior (which is rare and should be clearly documented).
Conclusion
When you have a limited number of cases to choose from, switch statements can help you avoid long if-else ladders and provide better readability and maintainability in certain situations.
Just remember the key components: the switch keyword to evaluate an expression, case labels for specific values, and most importantly, the break statement to prevent unwanted "fall-through" behavior. Mastering switch will add a valuable tool to your C++ programming toolkit!