第 18.4 節
enum class
0瀏覽次數0訪問次數--跳出率--平均停留
本節解決什麼問題
C 語言的 enum 有幾個問題:
- 名字污染:枚舉值會泄漏到其所在的作用域,例如
enum Color { red, green };寫完後,red就成了全局名字,不能再用於別的枚舉。 - 隱式轉整數:枚舉值會悄悄變成整數參與運算(
red + 1合法但通常沒有意義)。 - 底層類型不確定:編譯器自行決定用多大空間存儲枚舉值。
enum class 解決了上述所有問題。
這個特性是什麼
enum class(強類型枚舉 / 限定作用域枚舉)是 C++11 引入的改進版枚舉:
- 枚舉值有作用域限定,需要用
Color::red訪問。 - 不會隱式轉換為整數。
- 可以指定底層類型(如
enum class Color : uint8_t)。
C++ 標準版本
C++11
需要的頭文件
不需要額外頭文件。enum class 是語言關鍵字。如果要使用 uint8_t 這類固定寬度整數作為底層類型,需要 #include <cstdint>。
基本語法
enum class 枚举名 : 底层类型
{
值1,
值2,
值3
};
// 访问
枚举名 变量 = 枚举名::值1;
常用用法
| 用法 | 説明 |
|---|---|
enum class E { A, B, C }; | 基本枚舉類 |
enum class E : uint8_t { A, B, C }; | 指定底層類型 |
E::A | 訪問枚舉值(帶作用域) |
static_cast<int>(E::A) | 顯式轉換(不會隱式轉換) |
switch (val) { case E::A: ... } | switch 匹配 |
示例代碼
示例 1:舊 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;
}
運行結果:
OldColor red = 0
Color::red = 0
示例 2:在示例 1 基礎上,指定底層類型和自定義值
#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;
}
運行結果:
Running
Stopped
sizeof(Status) = 1 byte(s)
Running = 10
示例 3:在示例 2 基礎上,enum class 在結構體中的應用
#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;
}
運行結果:
Alice grade: A (优秀)
Bob grade: C (中等)
Alice has higher grade
運行結果
見上方每個示例的"運行結果"。
示例中的關鍵語法解釋
| 示例 | 講了什麼 | 新出現的語法 | 為什麼這樣寫 | 注意事項 |
|---|---|---|---|---|
| 示例 1 | 舊 enum 問題 vs enum class | enum class、static_cast<int>() | 舊 enum 名字污染、隱式轉 int;enum class 解決 | 需要整數值時必須顯式轉換 |
| 示例 2 | 指定底層類型和 switch 用法 | enum class : uint8_t、switch + enum class | 指定底層類型能節省內存(如嵌入式場景) | sizeof(enum class) 不等於成員個數 |
| 示例 3 | 在 struct 中使用 enum class | enum class 做 struct 成員、比較操作 | 表示狀態、等級等有限取值集合 | enum class 支持 ==, <, > 等比較 |
enum class 適合表示狀態和選項
enum class 最適合表示“有限個離散取值”,比如機器人狀態、任務階段、通信協議命令、UI 模式。
示例 4:用 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;
}
運行結果:
execute task
如果用 int state = 1,讀代碼的人不知道 1 是什麼;如果用 enum class RobotState::Running,語義直接寫在類型裏,而且不會和其他枚舉的 Running 混用。
常見錯誤
錯誤 1:直接拿 enum class 值做數組下標
enum class Color { red, green, blue };
int counts[3];
counts[Color::red]; // ❌ 编译错误!不会隐式转换
正確做法:counts[static_cast<int>(Color::red)],或者在這種場景考慮用 map。
錯誤 2:忘記寫作用域前綴
enum class Status { Running, Stopped };
Status s = Running; // ❌ 编译错误!缺少 Status::
正確做法:Status s = Status::Running;
錯誤 3:switch 中混用不同 enum class 的值
switch (status)
{
case Status::Running: // ✅ 正确
case Machine::Running: // ❌ 编译错误!不同枚举类型
break;
}
正確做法:switch 中 case 必須和 switch 表達式是同一枚舉類型。
使用建議
- 永遠用
enum class而不是舊的enum:類型安全、作用域清晰。 - 可以指定底層類型:嵌入式場景用
enum class : uint8_t節省空間。 - 需要整數值時顯式用
static_cast:不要指望隱式轉換。 - enum class 仍然是整數,可以 switch:配合
default分支處理未知值。
小結
enum class避免名字污染,枚舉值通過枚举名::值訪問。- 不會隱式轉換為整數,需要
static_cast顯式轉換。 - 可以指定底層類型(
enum class E : uint8_t)。 - 適用於表示狀態、等級、選項等有限的離散取值集合。