C++11中enum class的使用

来源:互联网 发布:清朝灭亡 知乎 编辑:程序博客网 时间:2024/05/19 13:58

枚举类型(enumeration)使我们可以将一组整型常量组织在一起。和类一样,每个枚举类型定义了一种新的类型。枚举属于字面值常量类型。

C++包含两种枚举:限定作用域的和不限定作用域的。这里主要介绍限定作用域的。不限定作用域的使用可以参考: http://blog.csdn.net/fengbingchun/article/details/51778977   。

C++11新标准引入了限定作用域的枚举类型(scoped enumeration)。定义限定作用域的枚举类型的一般形式是:首先是关键字enum class(或者等价地使用enum struct),随后是枚举类型名字以及用花括号括起来的以逗号分隔的枚举成员(enumerator)列表,最后是一个分号。

枚举作用域(enumeration scope)是指枚举类型的成员的名字的作用域,起自其声明之处,终止枚举定义结束之处。C语言规定,枚举类型的成员(enumerator)的可见范围被提升至该枚举类型所在的作用域内。这被认为有可能污染了外部的作用域,为此,C++11引入了枚举类(enum class)解决此问题。

定义不限定作用域的枚举类型(unscoped enumeration)时省略掉关键字class(或struct),枚举类型的名字是可选的。

如果enum是未命名的,则我们只能在定义该enum时定义它的对象。和类的定义类似,我们需要在enum定义的右侧花括号和最后的分号之间提供逗号分隔的声明列表。

枚举成员:在限定作用域的枚举类型中,枚举成员的名字遵循常规的作用域准则,并且在枚举类型的作用域外是不可访问的。与之相反,在不限定作用域的枚举类型中,枚举成员的作用域与枚举类型本身的作用域相同。

默认情况下,枚举值从0开始,依次加1.不过我们也能为一个或几个枚举成员指定专门的值。枚举值不一定唯一。如果我们没有显示地提供初始值,则当前枚举成员的值等于之前枚举成员的值加1.枚举成员是const,因此在初始化枚举成员时提供的初始值必须是常量表达式。也就是说,每个枚举成员本身就是一条常量表达式,我们可以在任何需要常量表达式的地方使用枚举成员。类似的,我们也可以将一个enum作为switch语句的表达式,而将枚举值作为case标签。出于同样的原因,我们还能将枚举类型作为一个非类型模板形参使用;或者在类的定义中初始化枚举类型的静态数据成员。

和类一样,枚举也定义新的类型:只要enum有名字,我们就能定义并初始化该类型的成员。要想初始化enum对象或者为enum对象赋值,必须使用该类型的一个枚举成员或者该类型的另一个对象

一个不限定作用域的枚举类型的对象或枚举成员自动地转换成整型。因此,我们可以在任何需要整型值的地方使用它们。而限定作用域的枚举类型不会进行隐式转换

指定enum的大小:尽管每个enum都定义了唯一的类型,但实际上enum是由某种整数类型表示的。在C++11标准中,我们可以在enum的名字后加上冒号以及我们想在该enum中使用的类型。如果我们没有指定enum的潜在类型,则默认情况下限定作用域的enum成员类型是int。对于不限定作用域的枚举类型来说,其枚举成员不存在默认类型,我们只知道成员的潜在类型足够大,肯定能够容纳枚举值。如果我们指定了枚举成员的潜在类型(包括对限定作用域的enum的隐式指定),则一旦某个枚举成员的值超出了该类型所能容纳的范围,将引发程序错误。

指定enum潜在类型的能力使得我们可以控制不同实现环境中使用的类型,我们将可以确保在一种实现环境中编译通过的程序所生成的代码与其他实现环境中生成的代码一致。

枚举类型的前置声明:在C++11新标准中,我们可以提前声明enum。enum的前置声明(无论隐式地还是显示地)必须指定其成员的大小。不限定作用域的,必须指定成员类型。限定作用域的枚举类型可以使用默认成员类型int。因为不限定作用域的enum未指定成员的默认大小,因此每个声明必须指定成员的大小。对于限定作用域的enum来说,我们可以不指定其成员的大小,这个值被隐式地定义成int。和其它声明语言一样,enum的声明和定义必须匹配,这意味着在该enum的所有声明和定义中成员的大小必须一致。而且,我们不能在同一个上下文中先声明一个不限定作用域的enum名字,然后再声明一个同名的限定作用域的enum。

形参匹配与枚举类型:要想初始化一个enum对象,必须使用该enum类型的另一个对象或者它的一个枚举成员。因此,即使某个整型值恰好与枚举成员的值相等,它也不能作为函数的enum实参使用。不限定作用域的枚举类型,潜在类型因机器而异。尽管我们不能直接将整型值传给enum实参,但是可以将一个不限定作用域的枚举类型的对象或枚举成员传给整型形参。此时,enum的值提升成int或更大的整型,实际提升的结果由枚举类型的潜在类型决定。

The enum classes("new enums",  "strong enums") address three problems with traditional C++ enumerations:

1. conventional enums implicitly convert to int, causing errors when someone does not want an enumeration to act as an integer.

2. conventional enums export their enumerators to the surrounding scope, causing name clashes.

3. the underlying type of an enum cannot be specified, causing confusion,compatibility problems, and makes forward declaration impossible.

The new enums are "enum class" because they combine aspects of traditional enumerations (names values) with aspects of classes (scoped members and absense of conversions).

         C++ has two kinds of enum: enum classes,Plain enums.

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "enum_class.hpp"#include <iostream>namespace enum_class_ {typedef short int16_t;////////////////////////////////////////////////////////////////////// reference: http://en.cppreference.com/w/cpp/language/enum// enum that takes 16 bitsenum smallenum : int16_t {a,b,c};// color may be red (value 0), yellow (value 1), green (value 20), or blue (value 21)enum color {red,yellow,green = 20,blue};// altitude may be altitude::high or altitude::lowenum class altitude : char {high = 'h',low = 'l', // C++11 allows the extra comma};// the constant d is 0, the constant e is 1, the constant f is 3enum {d,e,f = e + 2};//enumeration types (both scoped and unscoped) can have overloaded operatorsstd::ostream& operator << (std::ostream& os, color c){switch (c) {case red: os << "red";    break;case yellow: os << "yellow"; break;case green: os << "green";  break;case blue: os << "blue";   break;default: os.setstate(std::ios_base::failbit);}return os;}std::ostream& operator << (std::ostream& os, altitude al){return os << static_cast<char>(al);}int test_enum_class_1(){color col = red;altitude a;a = altitude::low;std::cout << "col = " << col << '\n'<< "a = " << a << '\n'<< "f = " << f << '\n';return 0;}////////////////////////////////////////////////////////////////////////// reference: https://stackoverflow.com/questions/18335861/why-is-enum-class-preferred-over-plain-enum// C++ has two kinds of enum: enum classes, Plain enumsenum Color { red1, green1, blue1 };                    // plain enumenum Card { red_card, green_card, yellow_card };    // another plain enumenum class Animal { dog, deer, cat, bird, human };  // enum classenum class Mammal { kangaroo, deer, human };        // another enum classint test_enum_class_2(){// examples of bad use of plain enums:Color color = Color::red1;Card card = Card::green_card;int num = color;    // no problemif (color == Card::red_card) // no problem (bad)std::cout << "bad" << std::endl;if (card == Color::green1)   // no problem (bad)std::cout << "bad" << std::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)//std::cout << "bad" << std::endl;//if (a == Mammal::deer) // error (good)//std::cout << "bad" << std::endl;return 0;}////////////////////////////////////////////////////////// reference: http://www.learncpp.com/cpp-tutorial/4-5a-enum-classes/int test_enum_class_3(){enum class Color { // "enum class" defines this as an scoped enumeration instead of a standard enumerationRED, // RED is inside the scope of ColorBLUE};enum class Fruit {BANANA, // BANANA is inside the scope of FruitAPPLE};Color color = Color::RED; // note: RED is not directly accessible any more, we have to use Color::REDFruit fruit = Fruit::BANANA; // note: BANANA is not directly accessible any more, we have to use Fruit::BANANA//if (color == fruit) // compile error here, as the compiler doesn't know how to compare different types Color and Fruit//std::cout << "color and fruit are equal\n";//else//std::cout << "color and fruit are not equal\n";if (color == Color::RED) // this is okaystd::cout << "The color is red!\n";else if (color == Color::BLUE)std::cout << "The color is blue!\n";//std::cout << color; // won't work, because there's no implicit conversion to intcolor = Color::BLUE;std::cout << static_cast<int>(color) << std::endl; // will print 1return 0;}} // namespace enum_class_

GitHub: https://github.com/fengbingchun/Messy_Test  

原创粉丝点击