列挙子の宣言、定義、使用

周知のとおり、C/C++言語では使用できる#defineとconst記号定数を作成し、一方で使用するenumこのツールは記号定数を作成できるだけでなく、新しいデータ型を定義することもできますが、一定の規則に従う必要があります。それでは一緒に見てみましょうenumの使い方。

ステップ(1)——列挙子の宣言と定義

(1) まず、次の文を見てください。

enum enumType {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};

この文には2つの働きがあります。

  • 第一に:enumType を新しいデータ型として宣言し、これを列挙(enumeration)と呼びます。
  • 第二に:Monday、Tuesday などを記号定数として宣言し、通常これらを列挙子と呼びます。その値はデフォルトでそれぞれ 0~6 です。(後で列挙子の値を明示的に初期化する方法を紹介します)

(2)次に、新しい列挙型 enumType を使ってこの型の変数を宣言します:enumType Weekday は、基本変数型 int を使って変数を宣言するのと同じです。例えば int a; また、列挙型を定義するときに列挙変数を定義することもできます。

enum enumType {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}Weekday;

しかし、基本変数型と異なる点は、強制変換を行わない限り、定義された列挙子だけをその列挙型の変数に代入できることです。例:Weekday = Monday; または Weekday = Sunday; 他の値を列挙変数に代入することはできません。例:Weekday = 10; これは許可されていません。10 は列挙子ではないからです。つまり Weekday は定義された Monday から Sunday までの定義済み列挙子のみにできるということです。しかし、これは絶対的なものではなく、6番目の項目で強制型変換を使って他の型の値を列挙変数に代入する方法を説明します。

(3)上記では非列挙子を列挙変数に代入できないと述べましたが、では列挙子を非列挙変数に代入することはできるでしょうか?例:int a=Monday;これは許可されます。列挙子は記号定数であり、この代入ではコンパイラが自動的に列挙子を int 型に変換するからです。

(4)前述のように列挙には代入演算が行えますが、列挙変数は算術演算を行うことができるでしょうか?

Weekday++;Weekday = Monday + Tuesday;

これは不正です。これらの操作は型の制限に違反する可能性があるためです。例えば:

Weekday = Sunday;
Weekday++;

Weekday が最初に列挙子の最後の値 Sunday(値は6)を代入され、さらにインクリメントすると、Weekday は 7 になりますが、enumType 型にとって 7 は無効です。

まとめ:列挙に対しては代入演算子のみが定義されており、列挙のための算術演算は定義されていません。

(5)列挙子に対して算術演算はできませんが、では列挙子は他の型の変数の演算に参加できるでしょうか?

int a;
a = 1 + Monday;

これは許可されます。コンパイラが自動的に列挙子を int 型に変換するからです。

(6)2番目で述べたこと:強制変換を行わない限り、定義された列挙子だけをその列挙型の変数に代入できる。つまり、強制変換を使えば他の型の値を列挙変数に代入できるということです:

Weekday = enumType(2);

次と同等です:

Weekday = Wednesday;
しかし、列挙の値の範囲を超える値を強制変換によって列挙変数に代入しようとすると、どのような結果になるでしょうか?
Weekday = enumType(20);

結果は未定義になります。この操作はエラーにはなりませんが、望んだ結果は得られません。

ステップ(2)——列挙子の値をカスタマイズする

(1)前述したように、定義によってenum enumType {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};列挙子 Monday、Tuesday などの値はデフォルトでそれぞれ 0~6 ですが、列挙子の値を明示的に設定することができます:

enum enumType {Monday=1, Tuesday=2, Wednesday=3, Thursday=4, Friday=5, Saturday=6, Sunday=7};

指定する値は整数でなければなりません!

(2)一部の列挙子の値だけを明示的に定義することもできます:

enum enumType {Monday=1, Tuesday, Wednesday=1, Thursday, Friday, Saturday, Sunday};

このようにすると、Monday、Wednesday はともに 1 と定義され、Tuesday=2 となり、Thursday、Friday、Saturday、Sunday の値はデフォルトでそれぞれ 2、3、4、5 になります。

まとめ:初期化されていない列挙子の値は、デフォルトでその前の列挙子の値より 1 大きくなります。

(3)2番目の項目はもう一つの現象も示しています。それは列挙子の値が同じになり得るということです。

ステップ(3)——列挙の値の範囲

前述のように、強制変換によって他の型の値を列挙変数に代入できます:

Weekday = enumType(2);

これは合法です;

しかし

Weekday = enumType(20);

これは非合法です。ここで列挙の値の範囲の概念が関係します:列挙の上限は、最大の列挙子より大きい最小の 2 のべき乗から 1 を引いたものです;

列挙の下限には2つのケースがあります:一つ目、列挙子の最小値が 0 以上の場合、列挙の下限は 0 です;二つ目、列挙子の最小値が 0 未満の場合、列挙の下限は最小の列挙子より小さい最大の 2 のべき乗に 1 を加えたものです。

例えば:

例えば次のように定義するとenum enumType1 { First=-5,Second=14,Third=10 };その場合、列挙の上限は 16-1=15(16 は最大の列挙子 14 より大きく、かつ 2 のべき乗です);列挙の下限は -8+1=-7(-8 は最小の列挙子 -5 より小さく、かつ 2 のべき乗です);

ステップ(4)——列挙の応用

個人的には、列挙と switch は最高の組み合わせだと思います:

enum enumType{Step0, Step1, Step2}Step=Step0; // 注意这里在声明枚举的时候直接定义了枚举变量 Step,并初始化为 Step0

switch (Step)x
{
  case Step0:{...;break;}
  case Step1:{...;break;}
  case Step2:{...;break;}
  default:break;
}

また、列挙にはもう一つ珍しい使い方があります。それはenum { one ,two ,three};名前を指定しないというものです。そうすると、当然ながら列挙型を定義することもできません。この場合、次と同等になります。static const int one = 0;このように3つの定数を定義するのと同じです。そして使うときはint no = one。


強型付け列挙

一、概要

強型付け列挙(Strongly-typed enums)は、列挙型と称され、C++11 の新しい構文であり、従来の C++ の列挙型が抱える欠点を解決するためのものです。従来の C++ では、列挙定数は外側のスコープに露出していました。そのため、同じスコープ内に2つの異なる列挙型があり、同じ列挙定数を含む場合、使用できないのです。例えば:

enum Side{Right,Left};
enum Thing{Wrong,Right};

これらは一緒に使うことができません。

もう一つの欠点は、従来の列挙値が常に暗黙的に整数型に変換され、ユーザーが型をカスタマイズできないことです。C++11 の強型付け列挙はこれらの問題を解決しました。

二、強型付け列挙

強型付け列挙は enum class 構文を使用して宣言します。次のとおりです:

enum class Enumeration{
    VAL1,
    VAL2,
    VAL3=100,
    VAL4
};

これにより、列挙型は安全になり、列挙値も暗黙的に整数に変換されず、整数値と比較することもできません。例えば(Enumeration::VAL4==10 はコンパイルエラーを引き起こします)。

また、列挙型が使用する型はデフォルトで int 型ですが、他の型を指定することもできます。例えば:

enum class Enum:unsigned int{VAL1,VAL2};

前述のとおり、強型付け列挙は、従来の列挙で異なる列挙型の下で同じ列挙値名が使えない問題を解決できます。列挙型の列挙名を使用するときは、所属するスコープを明示しなければなりません。例えば:Enum::VAL1 のように。単独の VAL1 はもはや意味を持ちません。

もう一つ説明に値する点として、C++11 では列挙型の前置宣言も可能です。例えば:

enum class Enum;
enum class Enum1:unsigned int;

三、プロジェクトにおける強型付け列挙のコード断片

1、画像処理

enum class Color{RED,BLUE,YELLOR,BLACK,WHITE};

2. 信号機

enum class TrafficLight{RED,YELLOR,GREEN};

強型付け列挙値は、従来の列挙の機能——列挙値の命名——を持ちながら、クラスの特徴——クラススコープのメンバーを持ち、デフォルトの型変換ができない——も併せ持っています。そのため、列挙クラス(enum class)とも呼ばれます。

列挙クラスの基盤となるデータ型は、符号付きまたは符号なしの整数型でなければなりません。例えば char、unsigned int、unsigned long などです。デフォルトは int です。

3. 前置宣言の応用

enmu class Clolor:char;            //前置声明枚举类
void Foo(Color*p);                     //前置声明的使用
//....................
enum class Color:char{RED,GREEN,BLACK,WHITE};      //前置声明的定义

参考:http://blog.csdn.net/u012333003/article/details/20612267