Chapter 18: Enum Types

枚举在由命名常量的固定列表所组成的用户定义类型。在下面的示例中,枚举类型被称为Color,并且包含三个常量:red,green与blue。

enum class Color { red, green, blue };

Color类型可以用来创建存储这些常量值中的一个的变量。枚举类常量必须以枚举名为前缀,如下所示。

int main()
{
    Color c = Color::red;
}

枚举示例

switch语句提供了枚举何时有用的良好示例。相比于使用普通常量,枚举具有允许程序员清晰表明变量应被允许包含什么值的优点。

switch(c)
{
    case Color::red: break;
    case Color::green: break;
    case Color::blue: break;
}

枚举常量值

通常,无需了解常量表示的底层值,但有时,了解底层值会非常有用。默认情况下,枚举列表中的第一个常量值为零,而后续的每个常量值比前一个大1。

enum class Color
{
    red, // 0
    green, // 1
    blue // 2
};

通过为常量赋值可以覆盖这些默认值。值可以被计算而无需唯一。未赋值的常量将会具有与前面已赋值的枚举值高的值。

enum class Color
{
    red = 5, // 5
    green = red, // 5
    blue = green + 2, // 7
    yellow // 8
};

枚举作用域

枚举并不一定要全局声明。它也可以被放置在类中作为类成员或是函数局部内。

class MyClass
{
    enum class Color { red, green, blue };
};
void myFunction()
{
    enum class Color { red, green, blue };
}

弱类型枚举

目前为止所描述的枚举类类型是由C++11引入为由C继承的弱类型枚举提供了一种安全的替换。旧的枚举类型定义与枚举类的定义方式相同,但无需class关键字。

// Weakly typed enum
enum Speed
{
    fast,
    normal,
    slow
};

对于弱类型枚举,指定的常量并不属于枚举名字的作用域。因而这样的枚举常量可以无需枚举名进行引用。

Speed s1 = fast;
Speed s2 = Speed::normal;

由于枚举类的类型安全以及其常量限定于枚举名内,因而推荐使用枚举类而不是弱类型枚举。因为枚举类是强类型的,它们不会隐式转换为整数类型。

// Weakly typed enum
enum Speed { fast, normal, slow };
Speed s = fast;
if (s == fast) {} // ok
if (s == 0) {} // ok
// Strongly typed enum
enum class Color { red, green, blue };
Color c = Color::red;
if (c == Color::red) {} // ok
if (c == 0) {} // error

C++20添加了使用using语句将枚举类导入到局部作用域的能力。这可以例在特定的作用域内像普通枚举成员一样访问枚举类成员,从而避免枚举类名的重复。确否不要将枚举导入到一个过大的作用域内,否则会丢失使用强类型枚举的主要好处。

#include <iostream>
using namespace std;
enum class Color { red, green, blue };
void colorPrint(Color c)
{
    // Import enum members to local scope
    using enum Color;
    switch (c)
    {
        case red: cout << "red";
        case green: cout << "green";
        case blue: cout << "blue";
    }
}

枚举常量类型

标准并没有定义普通枚举底层的整数类型,并且会随着不同的实现而变化。相对应地,枚举类默认总是使用int类型。对于两种枚举类型,类型可以覆盖为另一种整数类型,如下面的示例所示。

// Enum with constant type set to unsigned short
enum class MyEnum : unsigned short {};