コンテンツにスキップ

最終更新:2026-10-12

C++ enum 列挙型

著者について:

個人公式アカウント:

wechat

伝統的な挙動

列挙には次のような問題があります:

  • スコープが制限されず、名前の衝突を起こしやすいです。例えば以下はコンパイルを通れません:

enum Color
{
    RED,
    BLUE
};
enum Feeling
{
    EXCITED,
    BLUE
};

int main()
{
    Color a = BLUE; // error
    Feeling b = EXCITED;
    std::cout << a << ":" << b << std::endl;
    return 0;
}
- intへ暗黙変換される - 列挙変数を表す実際の型を明示的に指定できず、そのため列挙型の前方宣言をサポートできません。

具体的な実装はこちら:tradition_color.cpp

定番のやり方

スコープが制限されないことによる名前の衝突問題を解決する簡単な方法のひとつは、列挙変数に名前を付けるときにプレフィックスを付けることです。例えば上の例を COLOR_BLUE や FEELING_BLUE に変更します。

一般に、一貫性のためにすべての定数にプレフィックスを統一して付けます。しかしこれでは列挙変数を定義するコードが煩わしくなります。Cプログラムではそうせざるを得ないかもしれません。しかしC++プログラマはおそらくこの方法を好まないでしょう。代替案は名前空間です:

namespace Color 
{
    enum Type
    {
        RED=15,
        YELLOW,
        BLUE
    };
};

こうすれば Color::Type c = Color::RED; として新しい列挙変数を定義できます。using namespace Color の後はプレフィックスを省略でき、コードが簡潔になります。ただし、名前空間は後から内容を追加できるため、提供されるスコープの閉じ性は高くありません。大きなプロジェクトでは、異なる人が異なるものに同じ列挙型名を付ける可能性が依然としてあります。

より「効果的」な方法は、クラスまたは構造体でスコープを限定することです。例えば:新しい変数を定義する方法は上の名前空間の場合と同じです。ただしこの場合、クラスが別の場所で内容を変更される心配はありません。ここでクラスではなく構造体を使うのは、これらの定数を公開アクセスさせたいからです。

struct Color1
{
    enum Type
    {
        RED=102,
        YELLOW,
        BLUE
    };
};

具体的な実装はこちら:classic_practice.cpp

C++11 の列挙クラス(enum class)

上のやり方は1つ目の問題を解決しましたが、残りの2つには手も足も出ません。幸いなことに、C++11標準では「列挙クラス」(enum class)が導入され、上記の問題をうまく解決できます。

  • 新しいenumのスコープはもはやグローバルではありません
  • 他の型へ暗黙変換できません
/**
 * @brief C++11的枚举类
 * 下面等价于enum class Color2:int
 */
enum class Color2
{
    RED=2,
    YELLOW,
    BLUE
};
Color2 c2 = Color2::RED;
cout << static_cast<int>(c2) << endl; //必须转!
  • enumの格納に特定の型を指定できます
enum class Color3:char;  // 前向声明

// 定义
enum class Color3:char 
{
    RED='r',
    BLUE
};
char c3 = static_cast<char>(Color3::RED);

具体的な実装はこちら:classic_practice.cpp

クラス内の列挙型

ときには、ある定数をクラス内でのみ有効にしたいことがあります。#define で定義されるマクロ定数はグローバルであり、この目的を達成できないため、const で修飾したデータメンバを使うことを思いつきます。const データメンバは確かに存在しますが、その意味は私たちの期待するものではありません。

const データメンバはあるオブジェクトの生存期間中においてのみ定数であり、クラス全体にとっては可変です。クラスは複数のオブジェクトを生成でき、異なるオブジェクトの const データメンバの値は異なり得るからです。

クラス宣言の中で const データメンバを初期化することはできません。以下の使い方は誤りです。クラスのオブジェクトが生成される前は、コンパイラは SIZE の値が何なのか知らないからです。(c++11標準より前)

class A 
{
  const int SIZE = 100;   // 错误,企图在类声明中初始化 const 数据成员 
  int array[SIZE];  // 错误,未知的 SIZE 
}; 

正しくは、クラスのコンストラクタの初期化リストで行います:

class A 
{
  A(int size);  // 构造函数 
  const int SIZE ;    
}; 
A::A(int size) : SIZE(size)  // 构造函数的定义
{ 

} 
A  a(100); // 对象 a 的 SIZE 值为 100 
A  b(200); // 对象 b 的 SIZE 值为 200 

では、クラス全体で一定の定数を作るにはどうすればよいのでしょうか?

const データメンバに期待するのはやめて、クラス内の列挙定数を使って実現すべきです。例えば:

class Person{
public:
    typedef enum {
        BOY = 0,
        GIRL
    }SexType;
};
//访问的时候通过,Person::BOY或者Person::GIRL来进行访问。

列挙定数はオブジェクトの記憶領域を占有せず、コンパイル時にすべて評価されます。

列挙定数の欠点は、その暗黙のデータ型が整数であり、最大値に限りがあって浮動小数点数を表せないことです。

関連トピック

コメント