枚举和枚举类

枚举

普通枚举

枚举的使用

枚举类型(enumeration)是C及C++中一个基本的内置类型,不过也是一个有点”奇怪”的类型。从枚举的本意上来讲,就是要定义一个类别,并穷举同一类别下的个体以供代码中使用。由于枚举来源于C,所以出于设计上的简单的目的,枚举值常常是对应到整型数值的一些名字,比如:

// 匿名枚举
enum {Red, Green, Blue};
// 有名枚举
enum Colors{Red, Green, Blue};

在枚举类型中的枚举值编译器会默认从0开始赋值,而后依次向下递增,也就是说Red=0,Green=1,Blue=2。

代码示例:

#include <iostream>
using namespace std;

enum Day {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
};

void test01() {
    Day day = Thursday;
    if (day == 3) {
        cout << "今天星期四, 明天星期五" << endl;
    }
    if (day == Thursday) {
        cout << "今天星期四, 明天星期五" << endl;
    }
}

int main() {
	test01();
	return 0;
}

程序会输出两行 “今天星期四, 明天星期五”

也就是说既可以用数字也可以用原文

当然也可以显示指定枚举常量的值, 后面没指定的就会依次递增:

enum Day {
    Monday = 1,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
};

void test01() {
    Day day = Thursday;
    if (day == 3) {
        cout << "今天星期四, 明天星期五" << endl;
    }
    if (day == Thursday) {
        cout << "今天星期四, 明天星期五" << endl;
    }
}

这样只会输入一条语句 “今天星期四, 明天星期五”

枚举成员的值
  • 枚举的成员不能可以在枚举之外进行赋值,会出错。只可以在enum列表中进行改变值
Thursday = 4;

如果再test01中加入这一句, 就会报错: 表达式必须是可以修改的左值

  • 如果一个成员改变,这个成员及之后的成员值都改变。但是前面的成员不变

也就是说我把周四改为100的话,那周五六日就是101, 102, 103, 但是前面的值不变

enum Day {
    Monday = 1,
    Tuesday,
    Wednesday,
    Thursday = 100,
    Friday,
    Saturday,
    Sunday
};
void test03() {
    cout << (int)Tuesday << endl; // 2
    cout << (int)Friday << endl; // 101
}
新增枚举成员
  • 定义的新成员是没有初始化值的,需要自己初始化,初始化时还需要强制类型转换,要不然会出错
enum color {red,green};
 
int main()
{
    enum color white; //定义一个新枚举成员,无初始值
 
    white=(enum color)4;
    printf("%d\n",white); //4
 
    white=red;
    printf("%d\n",white); //0
 
    return 0;
}
枚举的缺陷

C/C++的enum有个很”奇怪” 的设定,就是具名(有名字)的enum类型的名字,以及 enum 的成员的名字都是全局可见的。这与 C++中具名的 namespace、class/struct 及 union 必须通过名字::成员名的方式访问相比是格格不入的,编码过程中一不小心程序员就容易遇到问题。比如∶

enum China {Shanghai, Dongjing, Beijing, Nanjing};
enum Japan {Dongjing, Daban, Hengbin, Fudao};

上面定义的两个枚举在编译的时候,编译器会报错,具体信息如下:

error C2365: “Dongjing”: 重定义;以前的定义是“枚举数”

错误的原因上面也提到了,在这两个具名的枚举中Dongjing是全局可见的,所有编译器就会提示其重定义了。

另外,由于C中枚举被设计为常量数值的”别名”的本性,所以枚举的成员总是可以被隐式地转换为整型,但是很多时候我们并不想这样。

枚举类

优点

针对枚举的缺陷,C++11标准引入了一种新的枚举类型,即枚举类,又称强类型枚举(strong-typed enum)。声明强类型枚举非常简单,只需要在 enum 后加上关键字 class。比如∶

// 定义强类型枚举
enum class Colors{Red, Green, Blue};

强类型枚举具有以下几点优势∶

  • 在枚举类中,枚举常量的作用域被限制在枚举类内部,而不会污染外部命名空间。使用枚举类时,需要使用作用域解析运算符 :: 来访问枚举常量。
  • ​ 强类型枚举只能是有名枚举,如果是匿名枚举会导致枚举值无法使用(因为没有作用域名称)。
  • 转换限制,强类型枚举成员的值不可以与整型隐式地相互转换。
  • 可以指定底层类型。强类型枚举默认的底层类型为 int,但也可以显式地指定底层类型,具体方法为在枚举名称后面加上∶type,其中 type 可以是除 wchar_t 以外的任何整型。比如:
enum class Colors :char { Red, Green, Blue };

wchar_t 是什么?

  • 双字节类型,或宽字符类型,是C/C++的一种扩展的存储方式,一般为16位或32位,所能表示的字符数远超char型。
  • 主要用在国际化程序的实现中,但它不等同于 unicode 编码。unicode 编码的字符一般以wchar_t类型存储。

再看普通枚举的例子, 再Day前面加上Class后, test01的代码应该为:

void test01() {
    Day day = Day::Thursday;
    if ((int)day == 3) {
        cout << "今天星期四, 明天星期五" << endl;
    }
    if (day == Day::Thursday) {
        cout << "今天星期四, 明天星期五" << endl;
    }
}

了解了强类型枚举的优势之后,我们再看一段程序:

enum class China { Shanghai, Dongjing, Beijing, Nanjing, };
enum class Japan :char { Dongjing, Daban, Hengbin, Fudao };
void test02()
{
    // int m = Shanghai;           // error
    // int n = China::Shanghai;    // error
    if ((int)China::Beijing >= 2)
    {
        cout << "ok!" << endl;
    }
    cout << "size1: " << sizeof(China::Dongjing) << endl;
    cout << "size2: " << sizeof(Japan::Dongjing) << endl;
}
  • 第5行:该行的代码有两处错误
  • 强类型枚举属于强作用于类型,不能直接使用,枚举值前必须加枚举类型
  • ​ 强类型枚举不会进行隐式类型转换,因此枚举值不能直接给int行变量赋值(虽然强类型枚举的枚举值默认就是整形,但其不能作为整形使用)。
  • 第6行:语法错误,将强类型枚举值作为整形使用,此处不会进行隐式类型转换
  • 第7行:语法正确,强类型枚举值在和整数比较之前做了强制类型转换。
  • 第11行:**打印的结果为4,**强类型枚举底层类型值默认为int,因此占用的内存是4个字节
  • 第12行:**打印的结果为1,**显示指定了强类型枚举值的类型为char,因此占用的内存大小为1个字节,这样我们就可以节省更多的内存空间了。
c++11对普通枚举的扩展

相比于原来的枚举,强类型枚举更像是一个属于C++的枚举。但为了配合新的枚举类型,C++11还对原有枚举类型进行了扩展:

  1. 原有枚举类型的底层类型在默认情况下,仍然由编译器来具体指定实现。但也可以跟强类型枚举类一样,显式地由程序员来指定。其指定的方式跟强类型枚举一样,都是枚举名称后面加上∶type,其中type 可以是除 wchar_t 以外的任何整型。比如∶
enum Colors : char { Red, Green, Blue };
  1. 关于作用域,在C++11中,枚举成员的名字除了会自动输出到父作用域,也可以在枚举类型定义的作用域内有效。比如:
enum Colors : char { Red, Green, Blue };
int main()
{
    Colors c1 = Green;          // C++11以前的用法
    Colors c2 = Colors::Green;  // C++11的扩展语法, 更严谨
    return 0;
}

上面程序中第4、5行的写法都是合法的。

C++11中对原有枚举类型的这两个扩展都保留了向后兼容性,也方便了程序员在代码中同时操作两种枚举类型。此外,我们在声明强类型枚举的时候,也可以使用关键字enum struct。实际上 enum struct 和enum class在语法上没有任何区别(enum class 的成员没有公有私有之分,也不会使用模板来支持泛化的声明 )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值