C++ 有一个奇怪的设定,有名字的 enum 类型的名字和 enum 成员的名字都是全局可见的。比如下面这种情况,就会导致编译错误。
enum Type { General, Light, Medium, Heavy };
enum Category { General, Pistol, MachineGun, Cannon }; // 无法通过编译
如果能够提示错误,那非常好。但是如果其中一个被新的 namespace 所包围,就很容易出现错误。
namespace T { enum Type { General, Light }; }
namespace { enum Category { General = 1, Pistol }; }
int main() {
T::Type t = T::Light;
if(t == General)
cout << "General Weapon" <<endl; // 输出 General Weapon
return 0;
}
上面的做法是明显错误的,不应该使用 Type::Light 来判断 Category::General 的数值。但是编译器并不会阻止编译(VC14 不会发出警告和错误),那么这就是一个非常难发现的 bug。
非强类型作用域,允许隐式转换为整型,占用存储空间以及符号不确定性,都是枚举类的缺点。
声明强类型枚举,只需要在 enum 后面加上关键字 class。
enum class Type { General, Light };
相对于普通枚举类型,强枚举类型几乎弥补了传统枚举类型的所有错误:
相比于原来的枚举,强类型枚举更像是一个属于 C++ 的枚举。但是为了配合新的枚举类型,C++ 11 对原有的枚举类型进行了拓展。
首先,传统枚举类型也可以指定底层数据类型,从而节省空间。其指定方式跟强类型枚举一样。形式为 enum Type : char { … }
第二个拓展是作用域的。在 C++ 11 中,枚举成员的名字除了会自动输出到父作用域,也可以在枚举类型定义的作用域有效。比如
enum Type { General, Light };
Type t1 = General;
Type t2 = Type::General;
上述两种方法都是合法的形式。程序员也就不会因为不同的枚举类型采用不同的方法来访问。
在声明强类型枚举的时候,也可以使用关键字 enum struct。但是实际上,enum struct 和 enum class 没有任何区别。因为强类型枚举可以看做既不占用内存又是公开的 static 常量,它完全没有共有私有之分,也不能对 enum class 使用模板来生成。
对于匿名 enum class,因为 enum class 是强类型作用域的,所以匿名的 enum class 没有任何作用。VC14 在试图定义匿名 enum class 时会报出错误。
转载请带上本文永久固定链接:http://www.gleam.graphics/class-enum.html