C++ enum枚举类型详解

enum枚举用法攻略》一节已经介绍过枚举数据类型,还记得吗?它们是由程序员定义的数据类型,由一组称为枚举量的值组成,枚举量代表整数常量。本节将进一步介绍枚举数据类型的应用,以及使用它们能做和不能做的事情。

在同一个语句中声明 enum 数据类型并定义变量

以下代码使用了两行来声明一个枚举数据类型,并定义了该类型的变量:

enum Car {PORSCHE, FERRARI, JAGUAR};
Car sportsCar;

但是,C++ 允许在同一个语句中声明一个枚举数据类型,并定义该类型的一个或多个变量。因此,上面的代码可以改写为如下形式:

enum Car {PORSCHE, FERRARI, JAGUAR} sportsCar;

以下语句不但声明了 Car 数据类型,而且定义了 2 个变量 myCar 和 yourCar:

enum Car {PORSCHE, FERRARI, JAGUAR} myCar, yourCar;

将整数赋值给 enum 变量

虽然枚举数据类型的枚举量在内存中是以整数形式存储的,但是,并不能直接将整数值赋给 enum 变量。例如,假设程序中包含以下声明:

enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY };
Day today;

现在可以编写以下赋值语句:

today = THURSDAY;

但是,正如前面已经介绍过的,以下语句是非法的。如果试图编译它,则会出现一个错误消息。

today = 3; //错误

在给 enum 变量赋值时,应该使用有效的枚举量。但是,如果某些情形要求必须将整数值存储在 enum 变量中,则可以通过强制转换的方式,将整数转换为 enum 数据类型,示例如下:

today = static_cast<Day>(3);

该语句的作用与以下语句是一样的:

today = THURSDAY;

将枚举量赋值给 int 变量

虽然不能直接将整数赋值给 enum 变量,但是,反过来却是可以的,即可以将枚举量赋值给整型变量。例如,以下代码将可以正常运行:
enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY };
int today = THURSDAY;
Day workday = FRIDAY;
int tomorrow = workday;
cout << today <<" "<< tomorrow << endl;
当该代码运行时,它将显示 3 4

使用数学运算符改变 enum 变量的值

虽然枚举量实际上就是整数,而且 enum 变量真正保存的也是整数值,但是,如果试图使用它们执行数学运算,那么还是会遇到问题。

例如,来看以下代码:

Day day1, day2; // 定义 2 个 Day 变量
day1 = TUESDAY; // 将 TUESDAY 赋值给 day1
day2 = day1 + 1; //错误!该语句不起作用

第 3 个语句之所以会出现问题,是因为表达式 day1+1 的结果为整数值 2,然后赋值运算符会试图将整数值 2 赋给 enum 变量 day2,但是前面已经介绍过,C++ 并不会隐式地将 int 转换为 Day 类型,所以出现了问题。

要解决该问题,可以如前文所述,通过强制转换的方式,将整数值结果转换为 Day 数据类型,示例如下:

day2 = static_cast<Day> (day1 + 1); //该语句有效

使用枚举量输出值

正如前文所述,将枚举量发送到 cout 将显示枚举量的整数值。例如,假设使用前面定义的 Day 类型,以下语句将显示 0:

cout << MONDAY << endl;

如果要让枚举量显示诸如“Monday”这样的字符串,则需要编写代码来产生所需的字 符串。例如,如果 workDay 是一个已经被初始化为某个值的 Day 变量,则以下switch语句将根据变量的值显示对应的日期名称:
switch(workDay)
{
    case MONDAY :
        cout <<"Monday";
        break;
    case TUESDAY :
        cout <<"Tuesday";
        break;
    case WEDNESDAY:
        cout <<"Wednesday";
        break;
    case THURSDAY :
        cout <<"Thursday";
        break;
    case FRIDAY :
        cout <<"Friday";
        break;
}

使用枚举量控制循环

因为枚举量是作为整数存储在内存中的,所以可以使用它们控制循环迭代的次数。但是,如前文所述,不能直接将数学运算的结果赋值给枚举量,而必须先将结果强制转换为 enum 数据类型。所以,不能直接对 enum 变量使用 ++ 或 -- 运算符。以下语句将无法运行。
Double sale, total = 0.0;
for ( Day workday = MONDAY; workday <= FRIDAY ; workday++) // 错误
{
    cout << "Enter the sales for day " << (workday +1) << ": ";
    cin >> sales;
    total += sales;
}
要解决该问题,可以将以上语句修改为如下形式:

for ( Day workday = MONDAY; workday <= FRIDAY; workday = static_cast<Day>(workday + 1))

但是,更简单的方法是将循环控制变量变成 int 类型。按照这个思路,可以将上面的语句修改如下:
for ( int workday = MONDAY; workday <= FRIDAY;workday++)
{
    cout << "Enter the sales for day " << (workday + 1) <<":";
    cin >> sales;
    total += sales;
}

使用C++ 11中的强类型 enum

C++ 不允许相同作用域内的多个枚举量具有相同的名称,也就是说,在同一作用域内,即使是两个不同的枚举数据类型,也不能定义或使用相同的枚举量名称作为自己的成员。但是,C++11 包含了一个新类型:enum,即所谓的强类型枚举,也称为 enum 类,可以摆脱这种限制。

以下是强类型 enum 声明的 2 个示例:

enum class Presidents { MCKINLEY, ROOSEVELT, TAFT };
enum class VicePresidents { ROOSEVELT, FAIRBANKS, SHERMAN };

以上语句定义了 2 个强类型 enum:Presidents 和 VicePresidents。注意,它们看起来和常规 enum 声明是一样的,区别在于,在 enum 后面多了一个单词 class。虽然这 2 个 enum 包含了相同的枚举量 ROOSEVELT,但是它们在编译时已经不会出错了。

但是,在使用强类型枚举数据类型时,必须给每个枚举量添加它所属 enum 名作为前缀,后接 :: 操作符。以下是 3 个示例:
Presidents prez = Presidents::ROOSEVELT;
VicePresidents vp1 = VicePresidents::ROOSEVELT;
VicePresidents vp2 = VicePresidents::SHERMAN;
第一个语句定义了名为 prez 的 Presidents 变量,并且使用了 Presidents::ROOSEVELT 枚举量作为它的初始化值;第二个语句定义了名为 vpl 的 VicePresidents 变量,并且使用了 VicePresidents::ROOSEVELT 枚举量作为它的初始化值;第三个语句定义了名为 vp2 的 VicePresidents 变量,并且使用了 VicePresidents::SHERMAN 枚举量作为它的初始化值。

请注意,即使枚举量 SHERMAN 是枚举数据类型中唯一的成员,也必须加上它所属的 enum 名称作为前缀。

以下是使用枚举量比较 prez 变量的if语句示例:
if (prez == Presidents::ROOSEVELT)
    cout <<"Roosevelt is president! \n";
强类型枚举量和常规枚举量一样,也是作为整数存储的,但是,如果要检索一个强类型枚举量底层的整数值,则必须使用强制转换运算符。以下示例可以将 Presidents::ROOSEVELT 枚举量底层的整数值赋值给变量 x:

int x = static_cast<int>(Presidents::ROOSEVELT);

以下是另外一个示例,它显示了 Presidents::ROOSEVELT 和 Presidents::TAFT 枚举量的整数值:

cout<<static_cast<int>(Presidents :: ROOSEVELT) << " " <<static_cast<int>(Presidents::TAFT) << endl;

在声明强类型 enum 时,可以选择性地指定任意整数数据类型作为底层类型。只要在 enum 名称后面加上一个冒号(:),然后跟上所需的数据类型即可。例如,以下语句声明了一个使用 char 数据类型作为其枚举量的 enum:

enum class Day : char { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY };

以下语句显示了另外一个示例。该语句声明了一个名为 Water 的 enum,使用了 unsigned 作为其枚举量的数据类型。此外,还给枚举量赋值了。

enum class Water : unsigned { FREEZING = 32, BOILING = 212 };

下面的程序演示了强类型枚举数据类型的用法:
#include <iostream>
using namespace std;

enum class Presidents { MCKINLEY, ROOSEVELT, TAFT };
enum class VicePresidents { ROOSEVELT, FAIRBANKS, SHERMAN };

int main()
{
    Presidents prez = Presidents::ROOSEVELT;
    VicePresidents vp1 = VicePresidents::ROOSEVELT;
    VicePresidents vp2 = VicePresidents::SHERMAN;
    cout << static_cast<int>(prez) << " " << static_cast<int>(vp1) << " " << static_cast<int> (vp2) << endl;
    return 0;
}
程序输出结果:

10 2