C++ 枚举类型
上一章我们谈到了从真实世界的值(如扑克牌中的大小和花色)到程序世界内部表示(如整数或字符串)的映射。虽然我们实现了牌面大小和整型数、花色和整型数之间的映射,但必须指出,映射本身并没有成为程序的一部分。
实际上,C++提供了一种称为“枚举类型”的特性使以下两点成为可能,一是将映射作为程序的一部分,一是定义了组成映射的值的集合。比如,牌的花色(Suit)和大小(Rank)可以以枚举的形式定义:
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES };
enum Rank { ACE=1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE,
TEN, JACK, QUEEN, KING };
默认情况下,枚举类型中的第一个值映射为0,第二个映射为1,以此类推。如在Suit类型中,CLUBS(梅花)使用整型数0表示, DIAMONDS(方块)使用1表示,等等。
Rank的定义中将ACE指定为1,覆盖了默认的映射值。其他值以自然的方式递推。
定义了这些类型之后,我们就可以在任何地方使用它们。比如,实例变量rank和suit可以分别用类型Rank和Suit来声明:
struct Card
{
Rank rank;
Suit suit;
Card (Suit s, Rank r);
};
构造函数的参数类型也相应改变了。现在,我们可以以枚举类型的值为参数创建Card对象:
Card card (DIAMONDS, JACK);
一般约定,枚举类型中值的名字全部用大写字母表示。上面代码要比下面使用整型数的方式清晰地多:
Card card (1, 11);
枚举类型中的值是用整型数表示的,所以可用作向量的下标。因此原来的print函数不加修改即可工作。不过buildDeck还是要做些修改,如下:
int index = 0;
for (Suit suit = CLUBS; suit <= SPADES; suit = Suit(suit+1)) {
for (Rank rank = ACE; rank <= KING; rank = Rank(rank+1)) {
deck[index].suit = suit;
deck[index].rank = rank;
index++;
}
}
从某种程度上说,枚举类型的使用会让代码的可读性更好,不过同时也带来了一点混乱。严格地讲,不允许在枚举类型上执行数学运算,如suit++是不合法的。 而另一方面,在表达式suit+1中,C++自动将枚举类型转换为整型数,然后我们可以将结果强制转换为枚举类型:
suit = Suit(suit+1);
rank = Rank(rank+1);
当然,还有一种更好的处理方法,那就是为枚举类型重载++操作符,但这已经超出本书的范围了。