In C++, an enumeration (enum) is a user-defined data type that consists of a set of named integer constants.
Enums help make code more readable and manageable by allowing you to work with named constants instead of numbers, making it clear which values are valid options for certain variables.
Syntax of Enumeration
enum EnumName { value1, value2, value3, ... };
1. Basic Enum Definition and Usage
Define a simple enum and use its values.
#include <iostream> using namespace std; enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }; int main() { Day today = TUESDAY; cout << "Today is day number: " << today << endl; return 0; }
Explanation:
- Day is an enum representing days of the week, where MONDAY is 0, TUESDAY is 1, and so on.
- Enum values are assigned starting from 0 by default.
Output:
Today is day number: 1
2. Specifying Custom Values in Enums
You can assign specific integer values to enum constants.
#include <iostream> using namespace std; enum Month { JAN = 1, // Start from 1 instead of 0 FEB, MAR, APR = 10, MAY, JUN }; int main() { Month m1 = FEB; Month m2 = APR; cout << "FEB is month number: " << m1 << endl; cout << "APR is month number: " << m2 << endl; return 0; }
Explanation:
- JAN is assigned 1, and the following values increase by 1.
- APR is explicitly set to 10, so MAY and JUN continue from there.
Output:
FEB is month number: 2 APR is month number: 10
3. Using Enums in Conditional Statements
Enums are helpful in conditional statements for better readability.
#include <iostream> using namespace std; enum Direction { NORTH, EAST, SOUTH, WEST }; int main() { Direction dir = EAST; if (dir == NORTH) { cout << "Moving North" << endl; } else if (dir == EAST) { cout << "Moving East" << endl; } else if (dir == SOUTH) { cout << "Moving South" << endl; } else if (dir == WEST) { cout << "Moving West" << endl; } return 0; }
Explanation:
- The Direction enum is used in an if-else statement, making the code clearer than using integer values.
Output:
Moving East
4. Enum in a switch Statement
Enums can be used in a switch statement for more concise logic.
#include <iostream> using namespace std; enum Color { RED, GREEN, BLUE }; int main() { Color color = GREEN; switch (color) { case RED: cout << "Color is Red" << endl; break; case GREEN: cout << "Color is Green" << endl; break; case BLUE: cout << "Color is Blue" << endl; break; default: cout << "Unknown Color" << endl; } return 0; }
Explanation:
- Color enum values are used as cases in a switch statement for clear, readable code.
Output:
Color is Green
5. Enum Scope with enum class (Strongly Typed Enum)
C++11 introduced enum class, which provides a scoped and strongly-typed enumeration.
#include <iostream> using namespace std; enum class Fruit { APPLE, BANANA, ORANGE }; int main() { Fruit fruit = Fruit::BANANA; if (fruit == Fruit::BANANA) { cout << "Selected fruit is Banana" << endl; } return 0; }
Explanation:
- Fruit::BANANA specifies the enum name scope, avoiding potential name conflicts.
- enum class enums do not implicitly convert to integers, improving type safety.
Output:
Selected fruit is Banana
6. Accessing Underlying Integer Values of Enums
You can explicitly convert enum values to their underlying integer values using static_cast.
#include <iostream> using namespace std; enum Status { SUCCESS = 0, FAILURE = -1, PENDING = 1 }; int main() { Status status = FAILURE; cout << "Status code: " << static_cast<int>(status) << endl; return 0; }
Explanation:
- static_cast<int>(status) converts the enum value FAILURE to -1, which is its underlying integer representation.
Output:
Status code: -1
7. Using Enums with Functions
Enums can be passed to functions as parameters for improved readability.
#include <iostream> using namespace std; enum Level { LOW, MEDIUM, HIGH }; void displayLevel(Level lvl) { switch (lvl) { case LOW: cout << "Level is Low" << endl; break; case MEDIUM: cout << "Level is Medium" << endl; break; case HIGH: cout << "Level is High" << endl; break; } } int main() { Level lvl = MEDIUM; displayLevel(lvl); return 0; }
Explanation:
- The displayLevel function takes Level as an argument, allowing it to use named constants instead of integers.
Output:
Level is Medium
8. Enum with enum class and switch Statement
Using enum class in a switch statement provides scoped and type-safe enum usage.
#include <iostream> using namespace std; enum class Season { SPRING, SUMMER, FALL, WINTER }; void displaySeason(Season season) { switch (season) { case Season::SPRING: cout << "It's Spring" << endl; break; case Season::SUMMER: cout << "It's Summer" << endl; break; case Season::FALL: cout << "It's Fall" << endl; break; case Season::WINTER: cout << "It's Winter" << endl; break; } } int main() { Season season = Season::FALL; displaySeason(season); return 0; }
Explanation:
- The Season enum class is scoped within Season::, allowing better organization and avoiding naming conflicts.
Output:
It's Fall
9. Enums with Custom Underlying Data Types
By default, enums are of type int, but you can specify another integer type if needed, such as unsigned int.
#include <iostream> using namespace std; enum class ErrorCode : unsigned int { NONE = 0, NOT_FOUND = 404, INTERNAL_ERROR = 500 }; int main() { ErrorCode code = ErrorCode::NOT_FOUND; cout << "Error code: " << static_cast<unsigned int>(code) << endl; return 0; }
Explanation:
- ErrorCode uses unsigned int as its underlying data type.
- static_cast<unsigned int>(code) converts ErrorCode::NOT_FOUND to its integer value.
Output:
Error code: 404
10. Iterating Over Enum Values
Enums are not iterable by default. To iterate over an enum, you can create an array or vector containing the enum values.
#include <iostream> #include <vector> using namespace std; enum Size { SMALL, MEDIUM, LARGE }; void displaySizes(const vector<Size>& sizes) { for (Size size : sizes) { switch (size) { case SMALL: cout << "Small size" << endl; break; case MEDIUM: cout << "Medium size" << endl; break; case LARGE: cout << "Large size" << endl; break; } } } int main() { vector<Size> sizes = {SMALL, MEDIUM, LARGE}; displaySizes(sizes); return 0; }
Explanation:
- sizes is a vector containing all enum values of Size.
- displaySizes iterates over the vector and uses a switch statement to print each size.
Output:
Small size Medium size Large size
Summary Table of Enum Usage
Feature | Example | Description |
---|---|---|
Basic Enum | enum Day { MON, TUE }; | Defines a simple enumeration |
Custom Values | enum Month { JAN = 1, FEB }; | Assigns custom integer values to enums |
Conditional Statement | if (dir == NORTH) { … } | Uses enum in if or else statements |
Switch with Enum | switch (color) { case RED: … } | Uses enum in a switch statement |
Scoped Enum (enum class) | enum class Fruit { APPLE, ORANGE }; | Defines a type-safe, scoped enum |
Access Integer Value | static_cast<int>(status) | Converts enum to its underlying integer value |
Enum in Function | void func(Level lvl) { … } | Passes enum as a function parameter |
Enum with Custom Type | enum class Code : unsigned int { … }; | Uses a custom integer type for an enum class |
Iterating Enum | for (Size s : sizes) { … } | Iterates over enum values using an array or list |
Key Takeaways
- Basic enums allow you to define named constants, making code more readable and less error-prone.
- Scoped enums (enum class) provide better type safety and avoid conflicts with other names.
- Enums can have custom underlying data types (e.g., unsigned int) and custom values.
- While enums are not inherently iterable, you can use arrays or vectors for enumeration iterations.
- Using switch statements with enums makes the code clear and readable, especially when handling a set of discrete values.