C++ - 列舉 (Enum)



在 C++ 中,列舉(或 enum)是一種使用者定義的資料型別,它由一組命名的整型常量組成。

建立(宣告)列舉型別

要建立列舉 (enum),請使用 **enum** 關鍵字,後跟列舉的名稱和進一步用花括號括起來的名值列表。

語法

以下是建立列舉的語法:

enum enumName {
   Enumerator_value1,
   Enumerator_value2,
   Enumerator_value3,
   // … So on
};

這裡,

  • **enum** 是宣告列舉型別的關鍵字。
  • **enumName** 是列舉的名稱。
  • Enumerator_Value1、Enumerator_Value1、Enumerator_Value1 等是整型常量。

訪問列舉

您可以透過在 int main() 函式體中用變數名宣告它並在需要時呼叫它來訪問列舉 (enum)。

語法

這是訪問或呼叫列舉的語法

enum enumName {
   Enumerator_value1,
   Enumerator_value2,
   Enumerator_value3,
   // … So on
};

// Creating variable and assigning value
enumName enam_var = value;

這裡,

  • **enumName** 是列舉的已宣告變數名。
  • **variableName** 是列舉器(在列舉中定義的值)的變數名。

C++ 列舉示例

在下面的示例中,我們聲明瞭一個列舉型別,聲明瞭一個列舉的變數/物件,並訪問了列舉常量。請考慮以下示例:

#include <iostream>
using namespace std;
// Define an enumeration called Day, for a days of week
enum Day {
   Sunday,      // 0
   Monday,      // 1
   Tuesday,     // 2
   Wednesday, // 3
   Thursday,     // 4
   Friday = 45,  // 45
   Saturday       // 46
};

int main() {
   // Declaring a variable for a day
   Day get1 = Wednesday;
   cout<<get1<<endl;

   cout<<Saturday<<endl;
   return 0;
}

輸出

3
46

解釋

在上面的程式碼中,預設情況下,每個星期的值都已顯式地分配了一個唯一的整數值,範圍從 0 到 6,分配給一週中的所有日子。但是,如果我們顯式地將值 45 分配給星期五,則列舉屬性將導致序列從該特定點繼續,因此星期五和星期六的剩餘值將分別變為 45 和 46,並在之後繼續完成序列。

C++ 列舉的型別

C++ 中通常有兩種型別的列舉:

1. 無作用域列舉

無作用域列舉是 C++ 中傳統的列舉形式。它們使用 enum 關鍵字定義,列舉器名稱在包含作用域中宣告。由於列舉器名稱被新增到周圍的作用域,如果沒有仔細管理,可能會導致名稱衝突,它可以直接在程式碼中使用,就像一組表示特定數字的標籤。

它會自動分配從零開始的整數值(除非顯式分配),並且可以隱式轉換為整數。

示例

#include <iostream>
using namespace std;

enum RGB {
   Red,    // 0
   Green,  // 1
   Blue    // 2
};

void printColor(RGB color) {
   switch (color) {
      case Red: cout << "Color is Red"; break;
      case Green: cout << "Color is Green"; break;
      case Blue: cout << "Color is Blue"; break;
   }
}

int main() {
   RGB myColor = Red;        // Here, no need to specify enum name
   int value = myColor;     // Implicit conversion to int

   cout << "Integer value: " << value << endl; // Outputs: 0
   printColor(myColor);      // Outputs: Color is Red

   return 0;
}

輸出

Integer value: 0
Color is Red

2. 有作用域列舉 (enum class)

有作用域列舉是在 C++11 中引入的,使用 enum class 定義。它們提供了更好的型別安全性和組織性,其中它們的列舉器名稱在列舉中具有作用域。這意味著將它們的標籤儲存在特定組中,因此在使用它們時需要提及組名。這有助於避免在不同組中具有類似標籤時造成混淆。

列舉器名稱在列舉型別中具有作用域,這意味著您必須使用列舉名稱來訪問它們。沒有隱式轉換為整數,這有助於增強型別安全性。

示例

#include <iostream>
using namespace std;

enum class Color {
   Red,    // Implicitly 0
   Green,  // Implicitly 1
   Blue    // Implicitly 2
};

// Usage
int main() {
   Color myColor = Color::Red;  // Must use enum name
   // int value = myColor;       // Error: no implicit conversion

   // Explicit conversion to int if needed
   int value = static_cast<int>(myColor);  // value = 0

   cout << "Integer value: " << value << endl; // Outputs: 0

   return 0;
}

輸出

Integer value: 0

有作用域列舉與無作用域列舉

特性 無作用域列舉 有作用域列舉 (enum class)
列舉器作用域 全域性作用域 列舉型別內的作用域
名稱衝突 可能 避免
隱式轉換
型別安全 較少 更多
底層型別 預設為 int 可以指定自定義型別

比較列舉值

列舉值可以像整數比較一樣進行比較。請考慮以下示例:

示例

#include <iostream>
using namespace std;
enum class Color {
   Red,
   Green,
   Blue
};
int main() {
   Color myColor = Color::Green;
   if (myColor == Color::Green) {
      cout << "The color is green!" << endl;
   } else {
      cout << "The color is not green." << endl;
   }
   return 0;
}

輸出

The color is green!

列舉作為函式引數

您可以將列舉作為引數傳遞給函式。要在函式中傳遞列舉作為引數,您需要指定列舉名稱及其例項。

示例

在下面的示例中,我們將列舉作為引數傳遞:

#include <iostream>
using namespace std;
enum class Color {
   Red,
   Green,
   Blue
};

// Function that takes an enum as a parameter
void printColor(Color color) {
   switch (color) {
      case Color::Red:
         cout << "Red" << endl;
         break;
      case Color::Green:
         cout << "Green" << endl;
         break;
      case Color::Blue:
         cout << "Blue" << endl;
         break;
   }
}

int main() {
   Color myColor = Color::Blue;
   printColor(myColor);  
   return 0;
}

輸出

Blue

列舉的常見用例

以下是列舉的一些常見用例:

1. 狀態管理

enum class GameState {
   MainMenu,
   Playing,
   Paused,
   GameOver
};

2. 配置選項

enum class LogLevel {
   Info,
   Warning,
   Error,
   Debug
};

3. 命令型別

enum class Command {
   Start,
   Stop,
   Pause,
   Resume
};

4. 方向和移動

enum class Direction {
   Up,
   Down,
   Left,
   Right
};

使用列舉的好處

  • **提高可讀性和可維護性** - 列舉為值提供了有意義的名稱,這使得程式碼更清晰、更易於理解和維護。
  • **型別安全和名稱空間管理** - C++ 中的列舉限制了分配的值,尤其是在有作用域的列舉中,這減少了錯誤並避免了名稱衝突。
  • **組織良好的程式碼結構** - 列舉有助於透過對相關常量進行分組來增強組織,從而提高程式碼可讀性,強制執行型別安全性,建立更清晰的函式介面,並促進更輕鬆的重構
  • **增強的功能** - 列舉與 switch 語句配合使用,並允許使用分配的值對底層型別進行顯式控制。

列舉的侷限性

儘管有好處,但它仍然有一些如下所述的侷限性:

  • **型別安全問題** - 無作用域列舉會導致名稱衝突並允許隱式轉換為整數,這會增加錯誤風險。
  • **功能有限** - 列舉具有一組固定的值,並且缺乏成員函式,無法在執行時擴充套件。
  • **除錯困難** - 偵錯程式可能會將列舉值顯示為整數,這使得難以解釋其含義。
廣告