Enum vs enum class in C++: Key Differences and Usage
enum defines unscoped enumerations where enumerator names leak into the surrounding scope and implicit conversions to integers are allowed. enum class creates scoped enumerations that prevent name conflicts and disallow implicit conversions, providing better type safety.Quick Comparison
This table summarizes the main differences between enum and enum class in C++.
| Feature | enum | enum class |
|---|---|---|
| Scope of enumerators | Global within the enclosing scope | Scoped inside the enum class |
| Implicit conversion to int | Allowed | Not allowed |
| Name conflicts | Possible due to unscoped names | No conflicts, names are scoped |
| Underlying type | Usually int, can be specified | Optional to specify, defaults to int |
| Type safety | Low, can mix with integers | High, strong typing enforced |
| Introduced in | C++98 | C++11 |
Key Differences
The traditional enum in C++ defines a set of named integer constants that are placed directly into the enclosing scope. This means you can use the enumerator names without qualifying them, but it also risks name clashes if different enums have the same enumerator names. Additionally, enum values implicitly convert to integers, which can lead to bugs if mixed unintentionally.
On the other hand, enum class (introduced in C++11) creates a scoped enumeration. The enumerator names are contained within the enum class scope, so you must qualify them with the enum class name. This prevents name conflicts. Also, enum class values do not implicitly convert to integers, improving type safety by forcing explicit casts when needed.
Furthermore, enum class allows specifying the underlying type explicitly, and if not specified, it defaults to int. This control over the underlying type can be useful for memory optimization or interfacing with other systems.
Code Comparison
#include <iostream> // Traditional enum enum Color { Red, Green, Blue }; int main() { Color c = Green; // No need to qualify int n = c; // Implicit conversion allowed std::cout << "Color value: " << n << std::endl; // Name conflict example int Red = 10; // Allowed, conflicts with enum Red std::cout << "Red variable: " << Red << std::endl; return 0; }
enum class Equivalent
#include <iostream> // Scoped enum class enum class Color { Red, Green, Blue }; int main() { Color c = Color::Green; // Must qualify enumerator // int n = c; // Error: no implicit conversion int n = static_cast<int>(c); // Explicit cast needed std::cout << "Color value: " << n << std::endl; int Red = 10; // No conflict with Color::Red std::cout << "Red variable: " << Red << std::endl; return 0; }
When to Use Which
Choose enum class when you want strong type safety, avoid name conflicts, and prefer scoped enumerators that require explicit qualification. It is the modern, safer choice for new C++ code.
Use traditional enum only when you need implicit conversions to integers or when working with legacy code that relies on unscoped enumerators. However, prefer enum class whenever possible to reduce bugs and improve code clarity.
Key Takeaways
enum class provides scoped enumerators and strong type safety.enum allows implicit int conversion and unscoped names, risking conflicts.enum class for modern, safer C++ code.enum class values to integers.enum only for legacy compatibility or when implicit conversion is needed.