enum class
What problem does this section solve?
There are several issues with C language's enum:
- Name Pollution: Enum values leak into their surrounding scope. For example, after writing
enum Color { red, green };,redbecomes a global name and can no longer be used in another enum. - Implicit conversion to integer: Enum values are implicitly converted to integers for operations (
red + 1is legal but usually meaningless). - Underlying Type Not Specified: The compiler determines how much memory to allocate for storing enum values.
enum class solved all the above problems.
What is this feature?
enum class (scoped enumeration) is an improved enumeration introduced in C++11:
- The enumeration values have scope limitations, and you need to access them using
Color::red. - does not implicitly convert to an integer.
- Can specify the underlying type (such as
enum class Color : uint8_t).
C++ standard version
C++11
Required header files
No need for extra headers. enum class is a language keyword. To use fixed-width integers like uint8_t as the underlying type, you need to include #include <cstdint>.
Basic Syntax
enum class 枚举名 : 底层类型
{
值1,
值2,
值3
};
// 访问
枚举名 变量 = 枚举名::值1;
Common Usage
| Usage | Explanation |
|---|---|
enum class E { A, B, C }; | Basic Enum Class |
| An enumeration (enum) type used to define a set of named constants. Typically used to represent a fixed set of related values, such as days of the week, states, or categories, improving code readability and type safety. | |
enum class E : uint8_t { A, B, C }; | specify the underlying type |
E::A | Accessing enum values (with scope) |
static_cast<int>(E::A) | Explicit conversion (no implicit conversion) |
switch (val) { case E::A: ... } | switch matching |
Example code
Example 1: Old enum vs enum class
#include <iostream>
// 旧式 enum(不推荐)
enum OldColor { red, green, blue };
// enum class(推荐)
enum class Color { red, green, blue };
int main()
{
// 旧式 enum:名字污染,red 直接可见
OldColor oc = red; // 直接写 red
int n = red; // 隐式转为 0
// enum class:需要带作用域
Color c = Color::red;
// int m = Color::red; // ❌ 编译错误!不会隐式转换为 int
int m = static_cast<int>(Color::red); // ✅ 显式转换
std::cout << "OldColor red = " << n << "\n";
std::cout << "Color::red = " << m << "\n";
return 0;
}
Results:
OldColor red = 0
Color::red = 0
Example 2: Based on Example 1, specifying underlying types and custom values
#include <cstdint>
#include <iostream>
// 指定底层类型为 uint8_t(只占一个字节)
enum class Status : uint8_t
{
Idle = 0,
Running = 10,
Paused = 20,
Stopped = 30
};
void print_status(Status s)
{
switch (s)
{
case Status::Idle:
std::cout << "Idle\n";
break;
case Status::Running:
std::cout << "Running\n";
break;
case Status::Paused:
std::cout << "Paused\n";
break;
case Status::Stopped:
std::cout << "Stopped\n";
break;
}
}
int main()
{
Status s1 = Status::Running;
print_status(s1);
print_status(Status::Stopped);
// 查看底层整数值
std::cout << "sizeof(Status) = " << sizeof(Status) << " byte(s)\n";
std::cout << "Running = " << static_cast<int>(Status::Running) << "\n";
return 0;
}
Results:
Running
Stopped
sizeof(Status) = 1 byte(s)
Running = 10
Example 3: Building on Example 2, the application of enum class within a struct.
#include <iostream>
#include <string>
enum class Grade
{
A = 90,
B = 80,
C = 70,
D = 60,
F = 0
};
struct Student
{
std::string name;
Grade grade;
};
std::string grade_to_string(Grade g)
{
switch (g)
{
case Grade::A: return "A (优秀)";
case Grade::B: return "B (良好)";
case Grade::C: return "C (中等)";
case Grade::D: return "D (及格)";
case Grade::F: return "F (不及格)";
default: return "未知";
}
}
int main()
{
Student s1{"Alice", Grade::A};
Student s2{"Bob", Grade::C};
std::cout << s1.name << " grade: " << grade_to_string(s1.grade) << "\n";
std::cout << s2.name << " grade: " << grade_to_string(s2.grade) << "\n";
// 比较(enum class 支持 ==, <, > 等)
if (s1.grade > s2.grade)
{
std::cout << s1.name << " has higher grade\n";
}
return 0;
}
Results:
Alice grade: A (优秀)
Bob grade: C (中等)
Alice has higher grade
runtime results
See the "running results" for each example above.
Key syntax explanation in the example
|Here is the translation of the provided Simplified Chinese Markdown fragment into natural American English, following all specified rules.
| Example | Discusses what | Newly emerged syntax | Why write it this way | Precautions |
|---|---|---|---|---|
| Example 1 | Old enum vs enum class | enum class、static_cast<int>() | Old enums have namespace pollution and implicit conversion to int; enum class resolves these issues. | Explicit conversion is required when integer values are needed. |
| Example 2 | Specify underlying types and switch usage | enum class : uint8_t、switch + enum class | Specifying the underlying type can save memory (e.g., in microcontroller scenarios). | sizeof(enum class) does not equal the number of members |
| Example 3 | Using enum class within a struct in C++ provides a way to encapsulate enumerated types with strong typing and scope control. Here's a concise guide: |
1. Basic Definition
struct Robot {
enum class Direction { Forward, Backward, Left, Right };
Direction currentDirection = Direction::Forward;
};
2. Accessing Members
Robot myRobot;
myRobot.currentDirection = Robot::Direction::Left;
3. Benefits
- Type Safety: Prevents implicit conversions to/from integers.
- Scoped Access: Requires explicit enum class namespacing (e.g.,
Robot::Direction::Forward). - Encapsulation: Keeps enums tied to the struct’s context, improving code organization.
4. Usage Example
void moveRobot(Robot& robot, Robot::Direction dir) {
robot.currentDirection = dir;
}
// Call
moveRobot(myRobot, Robot::Direction::Right);
5. Best Practices
- Prefer
enum classover plainenumfor safety. - Use it for attributes closely related to the struct’s purpose (e.g., states, modes).
- Combine with
structmember functions for cohesive design.
This pattern is common in robotics (e.g., defining sensor states or motor commands) and aligns with clean, maintainable code principles.|Using enum class as struct member, comparison operations|A finite set of values representing states, levels, etc.|Enum class supports comparisons using ==, <, >, etc.|
Enum class is well-suited for representing states and options.
enum class is best for representing "a limited number of discrete values," such as robot states, task phases, communication protocol commands, and UI modes.
Example 4: Representing robot states with enum class
#include <iostream>
enum class RobotState
{
Idle,
Running,
Error
};
void handle_state(RobotState state)
{
switch (state)
{
case RobotState::Idle:
std::cout << "wait for command\n";
break;
case RobotState::Running:
std::cout << "execute task\n";
break;
case RobotState::Error:
std::cout << "stop and report error\n";
break;
}
}
int main()
{
// 程序从 main 函数开始执行,下面的语句会按顺序运行。
RobotState state = RobotState::Running;
handle_state(state);
// 返回 0 表示程序正常结束。
return 0;
}
Results:
execute task
If using int state = 1, readers won’t know what 1 is; if using enum class RobotState::Running, the semantics are directly written in the type and won’t be confused with other enums’ Running.
Common Errors
Error 1: Directly using enum class values as array subscripts
enum class Color { red, green, blue };
int counts[3];
counts[Color::red]; // ❌ 编译错误!不会隐式转换
The correct approach: counts[static_cast<int>(Color::red)], or consider using a map in this scenario.
Error 2: forgetting to write the scope prefix
enum class Status { Running, Stopped };
Status s = Running; // ❌ 编译错误!缺少 Status::
Correct approach: Status s = Status::Running;
Error 3: Mixing different enum class values in switch statement
switch (status)
{
case Status::Running: // ✅ 正确
case Machine::Running: // ❌ 编译错误!不同枚举类型
break;
}
Correct practice: in a switch statement, the case labels must be of the same enumeration type as the switch expression.
使用建议
- 明确目标:在开始前确定您的具体需求,以便选择最合适的工具或教程。
- 充分利用资源:参考官方文档、教程和博客,这些资料能帮助您快速上手并解决问题。
- 实践应用:通过动手操作项目或编写代码来巩固学习成果,提升实际操作能力。
- 问题解决:遇到困难时,查阅参考资料或寻求社区支持,逐步培养独立解决问题的能力。
- 分享经验:完成项目后,可以撰写文章或博客分享心得,帮助其他学习者。
如果需要针对特定领域(如单片机、机器人或环境搭建)的进一步建议,请提供更多信息,我将为您细化内容。
- Always use
enum classinstead of the oldenum: type-safe, clear scoping. - Can specify underlying type: Used in embedded scenarios with
enum class : uint8_tto save space. - Use
static_castexplicitly when an integer value is required: Do not rely on implicit conversion. - Enum classes are still integers, and can be switched on: combine with
defaultbranch handling for unknown values.
Summary
enum classavoids name pollution by accessing enum values through枚举名::值.- Does not implicitly convert to an integer, requiring
static_castexplicit conversion. - can specify the underlying type (
enum class E : uint8_t). - Suitable for representing a finite discrete set of values such as states, levels, or options.