Skip to content

Last updated:2026-10-12

C++ enum Enumerated Types

About the Author

WeChat official account:

wechat

Traditional Behavior

Enumerations have the following problems:

  • Unrestricted scope, which easily leads to naming conflicts. For example, the following fails to compile:

enum Color
{
    RED,
    BLUE
};
enum Feeling
{
    EXCITED,
    BLUE
};

int main()
{
    Color a = BLUE; // error
    Feeling b = EXCITED;
    std::cout << a << ":" << b << std::endl;
    return 0;
}
- Implicit conversion to int - The actual type used to represent the enumeration variable cannot be explicitly specified, so forward declaration of enumeration types is not supported.

See the concrete implementation at: tradition_color.cpp

Classic Practice

A simple way to solve the naming conflicts caused by the unrestricted scope is to add a prefix when naming enumeration values, e.g. changing the example above to COLOR_BLUE and FEELING_BLUE.

Generally speaking, for the sake of consistency we prefix all the constants. But code that defines enumerations this way looks cumbersome. C programs may have to do it this way, though C++ programmers probably dislike this approach. The alternative is a namespace:

namespace Color 
{
    enum Type
    {
        RED=15,
        YELLOW,
        BLUE
    };
};

After that, you can define a new enumeration variable with Color::Type c = Color::RED;. After using namespace Color, the prefix can even be omitted, which simplifies the code. However, because a namespace can be extended with more content later on, the scope it provides is not very well sealed. In a large project, it is still possible for different people to give the same enumeration type name to different things.

A more "effective" approach is to use a class or a struct to restrict the scope, for example: defining new variables works the same way as with the namespace above, but now you need not worry about the class being modified elsewhere. A struct is used here rather than a class because we want these constants to be publicly accessible in the first place.

struct Color1
{
    enum Type
    {
        RED=102,
        YELLOW,
        BLUE
    };
};

See the concrete implementation at: classic_practice.cpp

C++11 Enum Classes

The approach above solves the first problem but is powerless against the other two. Fortunately, the C++11 standard introduced "enum classes", which solve the problems above rather well.

  • The scope of the new enum is no longer global
  • No implicit conversion to other types
/**
 * @brief C++11的枚举类
 * 下面等价于enum class Color2:int
 */
enum class Color2
{
    RED=2,
    YELLOW,
    BLUE
};
Color2 c2 = Color2::RED;
cout << static_cast<int>(c2) << endl; //必须转!
  • A specific type can be specified to store the enum
enum class Color3:char;  // 前向声明

// 定义
enum class Color3:char 
{
    RED='r',
    BLUE
};
char c3 = static_cast<char>(Color3::RED);

See the concrete implementation at: classic_practice.cpp

Enumerated Types in Classes

Sometimes we want certain constants to be valid only inside a class. Since macros defined by #define are global, they cannot achieve this, so we think of using const-qualified data members instead. const data members do exist, but their meaning is not what we expect.

A const data member is constant only within the lifetime of a single object; for the class as a whole it is mutable, because the class can create multiple objects, and the const data members of different objects can have different values.

A const data member cannot be initialized in the class declaration. The following usage is wrong, because when no object of the class has been created, the compiler does not know what the value of SIZE is. (Before the C++11 standard)

class A 
{
  const int SIZE = 100;   // 错误,企图在类声明中初始化 const 数据成员 
  int array[SIZE];  // 错误,未知的 SIZE 
}; 

The correct place is the initializer list of the class's constructor:

class A 
{
  A(int size);  // 构造函数 
  const int SIZE ;    
}; 
A::A(int size) : SIZE(size)  // 构造函数的定义
{ 

} 
A  a(100); // 对象 a 的 SIZE 值为 100 
A  b(200); // 对象 b 的 SIZE 值为 200 

How can we establish a constant that holds throughout the whole class?

Do not count on const data members; use enumeration constants in the class instead. For example:

class Person{
public:
    typedef enum {
        BOY = 0,
        GIRL
    }SexType;
};
//访问的时候通过,Person::BOY或者Person::GIRL来进行访问。

Enumeration constants occupy no storage space in the object; they are all evaluated at compile time.

The drawback of enumeration constants is that their implicit data type is integer, their maximum value is limited, and they cannot represent floating point.

Comments