为什么枚举类优先于普通枚举?

我听到一些人build议在C ++中使用枚举 ,因为它们的types安全

但是这到底意味着什么呢?

C ++有两种enum

  1. enum class es
  2. 平原enum

以下是一些如何声明它们的例子:

  enum class Color { red, green, blue }; // enum class enum Animal { dog, cat, bird, human }; // plain enum 

两者有什么区别?

  • enum class es – 枚举器名称是枚举的本地和它们的值隐式转换为其他types(如另一个enumint

  • Plain enum s – 枚举器名称与枚举的范围相同,并且它们的值隐式转换为整数和其他types

例:

 enum Color { red, green, blue }; // plain enum enum Card { red_card, green_card, yellow_card }; // another plain enum enum class Animal { dog, deer, cat, bird, human }; // enum class enum class Mammal { kangaroo, deer, human }; // another enum class void fun() { // examples of bad use of plain enums: Color color = Color::red; Card card = Card::green_card; int num = color; // no problem if (color == Card::red_card) // no problem (bad) cout << "bad" << endl; if (card == Color::green) // no problem (bad) cout << "bad" << endl; // examples of good use of enum classes (safe) Animal a = Animal::deer; Mammal m = Mammal::deer; int num2 = a; // error if (m == a) // error (good) cout << "bad" << endl; if (a == Mammal::deer) // error (good) cout << "bad" << endl; } 

结论:

enum class es应该是首选,因为它们导致更less的可能导致错误的意外。

来自Bjarne Stroustrup的C ++ 11 FAQ :

enum class es(“new enums”,“strong enums”)解决了传统C ++枚举的三个问题:

  • 常规枚举隐式转换为int,导致错误,当有人不希望枚举作为一个整数。
  • 常规枚举将其枚举器导出到周围的范围,导致名称冲突。
  • 不能指定enum的基础types,导致混淆,兼容性问题,并使前向声明变得不可能。

新枚举是“枚举类”,因为它们将传统枚举(名称值)的方面与类(范围成员和缺乏转换)的方面结合在一起。

所以,正如其他用户所说,“强枚举”会使代码更安全。

“经典” enum的基础types应该是一个足够大的整数types,以适应enum所有值; 这通常是一个int 。 同样,每个枚举types应该与char或有符号/无符号整数types兼容。

这是一个enum基础types必须的广泛描述,所以每个编译器都会自己对经典enum的基本types进行enum ,有时结果可能会令人惊讶。

例如,我曾经看过很多这样的代码:

 enum E_MY_FAVOURITE_FRUITS { E_APPLE = 0x01, E_WATERMELON = 0x02, E_COCONUT = 0x04, E_STRAWBERRY = 0x08, E_CHERRY = 0x10, E_PINEAPPLE = 0x20, E_BANANA = 0x40, E_MANGO = 0x80, E_MY_FAVOURITE_FRUITS_FORCE8 = 0xFF // 'Force' 8bits, how can you tell? }; 

在上面的代码中,一些天真的编码器认为编译器会将E_MY_FAVOURITE_FRUITS值存储为一个无符号的8位types…但是没有任何保证:编译器可以selectunsigned charintshort ,其中任何types都是大的足以适应在enum看到的所有值。 添加字段E_MY_FAVOURITE_FRUITS_FORCE8是一个负担,并且不会强制编译器对enum的基础types做出任何select。

如果有一些代码依赖于types大小和/或者假设E_MY_FAVOURITE_FRUITS会有一定的宽度(例如:序列化例程),那么这个代码可能会以一些奇怪的方式运行,这取决于编译器的想法。

而更糟糕的是,如果一些同事不小心增加了我们的enum的新价值:

  E_DEVIL_FRUIT = 0x100, // New fruit, with value greater than 8bits 

编译器不会抱怨! 它只是调整types以适应enum所有值(假定编译器使用的是可能的最小types,这是我们不能做的假设)。 这个简单和粗心的除了可以微妙的破解相关的代码。

因为C ++ 11可以指定enumenum class的基础types(感谢rdb ),所以这个问题是整齐地解决:

 enum class E_MY_FAVOURITE_FRUITS : unsigned char { E_APPLE = 0x01, E_WATERMELON = 0x02, E_COCONUT = 0x04, E_STRAWBERRY = 0x08, E_CHERRY = 0x10, E_PINEAPPLE = 0x20, E_BANANA = 0x40, E_MANGO = 0x80, E_DEVIL_FRUIT = 0x100, // Warning!: constant value truncated }; 

如果某个字段的expression式超出此types的范围,则指定基础types,编译器将会投诉,而不是更改基础types。

我认为这是一个很好的安全改进。

编辑

那么为什么枚举类比普通枚举首选呢? ,如果我们可以selectscoped( enum class )和unscoped( enum )枚举的基础types,还有什么使enum class更好的select?

  • 它们不会隐式转换为int
  • 他们不污染周围的名字空间。
  • 他们可以被提前宣布。

使用枚举类超过正常枚举的基本优点是,你可能有两个不同的枚举相同的枚举variables,仍然可以解决它们(这已被提到OP types安全

例如:

 enum class Color1 { red, green, blue }; //this will compile enum class Color2 { red, green, blue }; enum Color1 { red, green, blue }; //this will not compile enum Color2 { red, green, blue }; 

至于基本枚举,编译器将无法区分red是否指向Color1Color2types,如下面的语句所示。

 enum Color1 { red, green, blue }; enum Color2 { red, green, blue }; int x = red; //Compile time error(which red are you refering to??) 

枚举用于表示一组整数值。

enum之后的class关键字指定枚举types是强types的,枚举types是作用域的。 这样, enum类可以防止意外滥用常量。

例如:

 enum class Animal{Dog, Cat, Tiger}; enum class Pets{Dog, Parrot}; 

在这里,我们不能混合动物和宠物的价值观。

 Animal a = Dog; // Error: which DOG? Animal a = Pets::Dog // Pets::Dog is not an Animal 
    Interesting Posts