Enumerations, commonly known as enums, are a user-defined data type in C++ that groups related constants together. They provide a way to assign names to integral constants, making the code more readable and maintainable. Enums are particularly useful when you have a set of related values that represent different states or categories.
In this tutorial, we'll explore traditional enums, scoped enums (using enum class), specifying underlying types for enums, and using enums in switch statements. Understanding these concepts will help you write cleaner and more efficient C++ code.
Enums allow you to define a set of named constants that represent specific values. This makes your code more readable and easier to manage, especially when dealing with a fixed set of related values. For example, instead of using magic numbers like 0, 1, and 2 to represent days of the week, you can use Monday, Tuesday, and Wednesday.
Enums are particularly useful in scenarios where you need to define a set of constants that are logically related but don't require complex operations. By using enums, you can make your code more expressive and less prone to errors.
A traditional enum is defined using the enum keyword followed by the name of the enum and a list of named constants enclosed in curly braces {}. Each constant is assigned an integer value starting from 0 by default, but you can explicitly assign values if needed.
1// basic_enum.cpp2#include <iostream>34enum Day {5Monday,6Tuesday,7Wednesday,8Thursday,9Friday,10Saturday,11Sunday12};1314int main() {15Day today = Wednesday;16std::cout << "Today is day number " << today << std::endl; // Output: Today is day number 217return 0;18}
Here, we explicitly assign values to each constant in the Color enum. This can be useful when you need specific integer values for your constants.
Traditional enums have some limitations, such as polluting the global namespace and allowing implicit conversions between enums and integers. To address these issues, C++11 introduced scoped enums using the enum class keyword. Scoped enums are defined within a scope, which prevents name clashes and requires explicit conversion when used.
1// basic_enum_class.cpp2#include <iostream>34enum class Weekday {5Monday,6Tuesday,7Wednesday,8Thursday,9Friday,10Saturday,11Sunday12};1314int main() {15Weekday today = Weekday::Wednesday;16std::cout << "Today is day number " << static_cast<int>(today) << std::endl; // Output: Today is day number 217return 0;18}
Here, we define a scoped enum Color with explicit values. Accessing and using these constants follows the same rules as in the previous example.
By default, enums use an integer type (int) to store their values. However, you can specify a different underlying type for an enum using the : TYPE syntax after the enum name. This can be useful when you want to save memory or ensure specific behavior.
1// specified_underlying_type.cpp2#include <iostream>34enum class Status : char {5Active = 'A',6Inactive = 'I'7};89int main() {10Status userStatus = Status::Active;11std::cout << "User status is: " << static_cast<char>(userStatus) << std::endl; // Output: User status is: A12return 0;13}
In this example, the Direction enum is used in a switch statement to determine the heading based on its value. This makes the code more readable and easier to manage.
Let's create a complete program that uses enums to represent different types of fruits and their corresponding nutritional values. We'll use both traditional enums and scoped enums, and demonstrate how to use them in a switch statement.
1// fruit_nutrition.cpp2#include <iostream>34enum Fruit {5Apple,6Banana,7Orange8};910enum class Nutrient {11Calories = 100,12Fiber = 5,13VitaminC = 1214};1516int main() {17Fruit myFruit = Banana;18Nutrient nutrientType = Nutrient::Calories;1920std::cout << "My favorite fruit is: ";21switch (myFruit) {22case Apple:23std::cout << "Apple" << std::endl;24break;25case Banana:26std::cout << "Banana" << std::endl;27break;28case Orange:29std::cout << "Orange" << std::endl;30break;31default:32std::cout << "Unknown fruit" << std::endl;33break;34}3536std::cout << "Nutrient type: ";37switch (nutrientType) {38case Nutrient::Calories:39std::cout << "Calories" << std::endl;40break;41case Nutrient::Fiber:42std::cout << "Fiber" << std::endl;43break;44case Nutrient::VitaminC:45std::cout << "Vitamin C" << std::endl;46break;47}4849return 0;50}
My favorite fruit is: Banana Nutrient type: Calories
In this program, we define two enums: Fruit for different types of fruits and Nutrient (a scoped enum) for different nutritional values. We then use these enums in switch statements to display information about the selected fruit and nutrient.
enum keyword. They are unscoped and can pollute the global namespace.enum class. They are scoped, preventing name clashes and requiring explicit conversions.: TYPE syntax.In the next tutorial, we'll explore unions, which allow you to store different data types in the same memory location. Unions are useful when you need to save memory and ensure that only one of several variables is active at any given time. Stay tuned!