详解C++11强类型枚举

    1.传统枚举类型的缺陷

    枚举类型是C/C++中用户自定义的构造类型,它是由用户定义的若干枚举常量的集合。枚举值对应整型数值,默认从0开始。比如定义一个描述性别的枚举类型。

    
    enum Gender{Male,Female};

    其中枚举值Male被编译器默认赋值为0,Female赋值为1。传统枚举类型在设计上会存在以下几个问题。

    (1)同作用域同名枚举值会报重定义错误。传统C++中枚举常量被暴漏在同一层作用域中,如果同一作用域下有两个不同的枚举类型,但含有同名的枚举常量也是会报编译错误的,比如:

    
    enum Fruits{Apple,Tomato,Orange};
    enum Vegetables{Cucumber,Tomato,Pepper}; //编译报Tomato重定义错误

    其中水果和蔬菜两个枚举类型中包含同名的Tomato枚举常量会导致编译错误。因为enum则是非强作用域类型,枚举常量可以直接访问,这种访问方式与C++中具名的namespace、class/struct以及union必须通过”名字::成员名”的访问方式大相径庭。

    (2)由于枚举类型被设计为常量数值的“别名”,所以枚举常量总是可以被隐式转换为整型,且用户无法为枚举常量定义类型。

    (3)枚举常量占用存储空间以及符号性不确定。C++标准规定C++枚举所基于的“基础类型”是由编译器来具体实现,这会导致枚举类型成员的基本类型存在不确定性问题,尤其是符号性问题,即。考察如下示例:

    
    enum A{A1=1,A2=2,ABig=0xFFFFFFFFU};
    enum B{B1=1,B2=2,BBig=0xFFFFFFFFFUL};
    
    int main()
    {
    	cout<<sizeof(A1)<<endl;	//4
    	cout<<ABig<<endl;		//4294967295
    	cout<<sizeof(B1)<<endl;	//8
    	cout<<BBig<<endl;		//68719476735
    }

    以上输出结果是在Linux平台下使用g++编译输出的结果,在VC++(VS2017)中的输出结果分别是4、-1、4和-1。可见不同编译器对枚举常量的整型类型的宽度和符号有着不同的实现。GNU C++会根据枚举数值的类型使用不同宽度和符号的整型,VC++则始终以有符号int来表示枚举常量。

    为了解决以上传统枚举类型的缺陷,C++11引入了强类型枚举解决了这些问题。

    2.强类型枚举

    非强作用域类型,允许隐式转换为整型,枚举常量占用存储空间以及符号性的不确定,都是枚举类缺点。针对这些缺点,C++11引入了一种新的枚举类型——强类型枚举(strong-typed enum)。

    强类型枚举使用enum class语法来声明:

    
    enum class Enumeration{VAL1,VAL2,VAL3=100,VAL4};

    强类型枚举具有如下几个优点:
    (1)强作用域,强类型枚举成员的名称不会被输出到其父作用域,所以不同枚举类型定义同名枚举成员编译不会报重定义错误。进而使用枚举类型的枚举成员时,必须指明所属范围,比如Enum::VAL1,而单独的VAL1则不再具有意义;
    (2)转换限制,强类型枚举成员的值不可以与整型发生隐式相互转换。比如比如Enumeration::VAL4==10;会触发编译错误;
    (3)可以指定底层类型。强类型枚举默认的底层类型是int,但也可以显示地指定底层类型。具体方法是在枚举名称后面加上”:type”,其中type可以是除wchar_t以外的任何整型。比如:

    
    enum class Type:char{Low,Middle,High};

    注意:
    (1)声明强类型枚举的时候,既可以使用关键字enum class,也可以使用enum struct。事实上,enum struct与enum class在语法上没有任何区别。
    (2)由于强类型枚举是强类型作用域的,故匿名的enum class可能什么都做不了,如下代码会报编译错误:

    
    enum class{General,Light,Medium,Heavy}weapon;
    int main()
    {
    weapon=Medium; //编译出错
    bool b=weapon == weapon::Medium; //编译出错
    return 0;
    }

    当然对于匿名强类型枚举我们还是可以使用decltype来获得其类型并进而使用,但是这样做可能违背强类型枚举进行匿名的初衷。

    3.C++11对传统枚举类型的扩展

    传统枚举类型为了配合C++11引入的强类型枚举,C++11对传统枚举类型进行了扩展。
    (1)底层的基本类型可以在枚举名称后加上”:type”,其中type可以是除wchar_t以外的任何整型,比如:

    
    enum Type:char{Low,Middle,High};

    (2)C++11中,枚举类型的成员可以在枚举类型的作用域内有效。比如:

    
    enum Type{Low, Middle, High };
    Type type1 = Middle;
    Type type2 = Type::Middle;

    其中Middle与Type::Middle都是合法的使用形式。

    以上就是详解C++11强类型枚举的详细内容,更多关于c++ 枚举的资料请关注lingkb其它相关文章!