S SmartDocs
Serie: C++ cpp 260 righe · Aggiornato 2026-04-03

enums.cpp

C++/Part2_物件導向/Ch07_結構體與列舉/enums.cpp

// ============================================================
// Ch07 — 列舉(enum / enum class)完整範例
// 編譯:g++ -std=c++17 -Wall -o enums enums.cpp
// ============================================================

#include <iostream>
#include <string>

// ============================================================
// 1. 傳統列舉(Unscoped Enum)
// ============================================================

// 傳統 enum — 值會洩漏到外圍作用域
enum Color {
    Red   = 0,
    Green = 1,
    Blue  = 2,
};

std::string colorToString(Color c) {
    switch (c) {
        case Red:   return "紅色";
        case Green: return "綠色";
        case Blue:  return "藍色";
    }
    return "未知";
}

// ============================================================
// 2. 限域列舉(enum class)— 推薦寫法
// ============================================================

// 方向列舉 — 使用 enum class 避免名稱汙染
enum class Direction {
    North,
    South,
    East,
    West,
};

std::string directionToString(Direction d) {
    switch (d) {
        case Direction::North: return "北";
        case Direction::South: return "南";
        case Direction::East:  return "東";
        case Direction::West:  return "西";
    }
    return "未知";
}

// ============================================================
// 3. 指定底層型別
// ============================================================

// 星期 — 指定底層型別為 unsigned char(節省空間)
enum class Weekday : unsigned char {
    Monday    = 1,
    Tuesday   = 2,
    Wednesday = 3,
    Thursday  = 4,
    Friday    = 5,
    Saturday  = 6,
    Sunday    = 7,
};

std::string weekdayToString(Weekday w) {
    switch (w) {
        case Weekday::Monday:    return "星期一";
        case Weekday::Tuesday:   return "星期二";
        case Weekday::Wednesday: return "星期三";
        case Weekday::Thursday:  return "星期四";
        case Weekday::Friday:    return "星期五";
        case Weekday::Saturday:  return "星期六";
        case Weekday::Sunday:    return "星期日";
    }
    return "未知";
}

bool isWeekend(Weekday w) {
    return w == Weekday::Saturday || w == Weekday::Sunday;
}

// ============================================================
// 4. 季節列舉 — 搭配函式使用
// ============================================================

enum class Season {
    Spring,
    Summer,
    Autumn,
    Winter,
};

struct SeasonInfo {
    std::string name;
    std::string description;
    int avgTempC;   // 平均氣溫(攝氏)
};

SeasonInfo getSeasonInfo(Season s) {
    switch (s) {
        case Season::Spring:
            return {"春天", "萬物復甦,百花盛開", 22};
        case Season::Summer:
            return {"夏天", "陽光普照,適合戶外活動", 32};
        case Season::Autumn:
            return {"秋天", "秋高氣爽,楓葉轉紅", 20};
        case Season::Winter:
            return {"冬天", "寒風刺骨,適合圍爐取暖", 10};
    }
    return {"未知", "", 0};
}

// ============================================================
// 5. HTTP 狀態碼 — enum class 搭配自訂數值
// ============================================================

enum class HttpStatus : int {
    OK           = 200,
    Created      = 201,
    BadRequest   = 400,
    Unauthorized = 401,
    Forbidden    = 403,
    NotFound     = 404,
    ServerError  = 500,
};

std::string httpStatusToString(HttpStatus status) {
    switch (status) {
        case HttpStatus::OK:           return "200 OK";
        case HttpStatus::Created:      return "201 Created";
        case HttpStatus::BadRequest:   return "400 Bad Request";
        case HttpStatus::Unauthorized: return "401 Unauthorized";
        case HttpStatus::Forbidden:    return "403 Forbidden";
        case HttpStatus::NotFound:     return "404 Not Found";
        case HttpStatus::ServerError:  return "500 Internal Server Error";
    }
    return "Unknown Status";
}

bool isSuccess(HttpStatus status) {
    int code = static_cast<int>(status);
    return code >= 200 && code < 300;
}

// ============================================================
// main
// ============================================================

int main() {
    std::cout << "========================================" << std::endl;
    std::cout << " Ch07 列舉(enum / enum class)完整範例" << std::endl;
    std::cout << "========================================\n" << std::endl;

    // ------ 1. 傳統列舉 ------
    std::cout << "【1】傳統列舉(Unscoped Enum)\n" << std::endl;

    Color c = Green;
    std::cout << "  顏色: " << colorToString(c) << std::endl;

    // 傳統 enum 可以隱式轉為 int
    int colorValue = c;
    std::cout << "  Green 的整數值: " << colorValue << std::endl;

    // 也可以直接拿來比較整數(這是傳統 enum 的缺點)
    if (c == 1) {
        std::cout << "  ⚠ 傳統 enum 可以與 int 直接比較(不安全)" << std::endl;
    }
    std::cout << std::endl;

    // ------ 2. 限域列舉 ------
    std::cout << "【2】限域列舉(enum class)— Direction\n" << std::endl;

    Direction dir = Direction::East;
    std::cout << "  方向: " << directionToString(dir) << std::endl;

    // enum class 不能隱式轉為 int
    // int dirValue = dir;  // 編譯錯誤!
    int dirValue = static_cast<int>(dir);
    std::cout << "  East 的整數值(顯式轉換): " << dirValue << std::endl;

    // 遍歷所有方向
    std::cout << "  所有方向:";
    for (int i = 0; i <= 3; ++i) {
        Direction d = static_cast<Direction>(i);
        std::cout << directionToString(d);
        if (i < 3) std::cout << "、";
    }
    std::cout << "\n" << std::endl;

    // ------ 3. 指定底層型別 — Weekday ------
    std::cout << "【3】指定底層型別 — Weekday\n" << std::endl;

    std::cout << "  Weekday 佔用空間: " << sizeof(Weekday) << " bytes" << std::endl;
    std::cout << "  (unsigned char = 1 byte)\n" << std::endl;

    Weekday days[] = {
        Weekday::Monday, Weekday::Tuesday, Weekday::Wednesday,
        Weekday::Thursday, Weekday::Friday, Weekday::Saturday,
        Weekday::Sunday,
    };

    for (auto day : days) {
        std::cout << "  " << weekdayToString(day)
                  << "(值=" << static_cast<int>(day) << ")"
                  << (isWeekend(day) ? " ← 週末!" : "")
                  << std::endl;
    }
    std::cout << std::endl;

    // ------ 4. 季節列舉搭配結構體 ------
    std::cout << "【4】Season 列舉搭配結構體回傳值\n" << std::endl;

    Season seasons[] = {Season::Spring, Season::Summer,
                        Season::Autumn, Season::Winter};

    for (auto s : seasons) {
        SeasonInfo info = getSeasonInfo(s);
        std::cout << "  " << info.name << ":"
                  << info.description
                  << "(平均 " << info.avgTempC << "°C)" << std::endl;
    }
    std::cout << std::endl;

    // ------ 5. HTTP 狀態碼 ------
    std::cout << "【5】HttpStatus — enum class 搭配自訂數值\n" << std::endl;

    HttpStatus codes[] = {
        HttpStatus::OK, HttpStatus::Created,
        HttpStatus::NotFound, HttpStatus::ServerError,
    };

    for (auto code : codes) {
        std::cout << "  " << httpStatusToString(code)
                  << " → " << (isSuccess(code) ? "成功" : "失敗")
                  << std::endl;
    }
    std::cout << std::endl;

    // ------ 6. enum class 的型別安全性示範 ------
    std::cout << "【6】型別安全性比較\n" << std::endl;

    std::cout << "  傳統 enum:" << std::endl;
    std::cout << "    Color c = Red;         // 不需前綴" << std::endl;
    std::cout << "    int v = c;             // 隱式轉換 ✓" << std::endl;
    std::cout << "    if (c == 0) ...        // 與 int 比較 ✓(危險)" << std::endl;

    std::cout << "\n  enum class:" << std::endl;
    std::cout << "    Direction d = Direction::East;  // 需要前綴" << std::endl;
    std::cout << "    int v = static_cast<int>(d);    // 需顯式轉換" << std::endl;
    std::cout << "    if (d == Direction::East) ...    // 只能同型別比較(安全)" << std::endl;

    std::cout << "\n  結論:優先使用 enum class,除非需要與 C 程式碼相容。" << std::endl;

    std::cout << "\n========================================" << std::endl;
    std::cout << " 範例結束" << std::endl;
    std::cout << "========================================" << std::endl;

    return 0;
}

Articoli correlati