第 18.4 節

enum class

0瀏覽次數0訪問次數--跳出率--平均停留

本節解決什麼問題

C 語言的 enum 有幾個問題:

  1. 名字汙染:枚舉值會洩漏到其所在的作用域,例如 enum Color { red, green }; 寫完後,red 就成了全局名字,不能再用於別的枚舉。
  2. 隱式轉整數:枚舉值會悄悄變成整數參與運算(red + 1 合法但通常沒有意義)。
  3. 底層類型不確定:編譯器自行決定用多大空間存儲枚舉值。

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 classenum classstatic_cast<int>()舊 enum 名字汙染、隱式轉 int;enum class 解決需要整數值時必須顯式轉換
示例 2指定底層類型和 switch 用法enum class : uint8_t、switch + enum class指定底層類型能節省內存(如嵌入式場景)sizeof(enum class) 不等於成員個數
示例 3在 struct 中使用 enum classenum 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 表達式是同一枚舉類型。

使用建議

  1. 永遠用 enum class 而不是舊的 enum:類型安全、作用域清晰。
  2. 可以指定底層類型:嵌入式場景用 enum class : uint8_t 節省空間。
  3. 需要整數值時顯式用 static_cast:不要指望隱式轉換。
  4. enum class 仍然是整數,可以 switch:配合 default 分支處理未知值。

小結

  • enum class 避免名字汙染,枚舉值通過 枚举名::值 訪問。
  • 不會隱式轉換為整數,需要 static_cast 顯式轉換。
  • 可以指定底層類型(enum class E : uint8_t)。
  • 適用於表示狀態、等級、選項等有限的離散取值集合。
音乐页