3.7  枚举类型

除了之前我们介绍的数值数据和文字数据之外,在现实世界中,常常还会遇到这样一类数据:一道单选题的答案只能是A、B、C、D四个选项中的某一个;红绿灯的颜色只能是红色,绿色和黄色中的某一种;一个人的性别只能是男性或者女性。这种数据都只有有限的几种可能值,其值也只能是这个范围内的某一个。为了抽象和表达这种特殊数据,C++提供了枚举机制。

使用C++的枚举机制,我们可以通过列举某种数据的所有可能值来定义一种新的数据类型,这种数据类型通常被称为枚举类型。反过来,当使用枚举类型来定义变量时,这个变量的取值也就限定在了枚举类型所列举出的可能取值范围内。定义一个枚举类型的语法格式如下:

enum 枚举类型名
{
// 可能的枚举值列表
}; // 注意,这里必须以分号表示结束

其中,enum是定义枚举类型的关键字;枚举类型名是所要创建的新数据类型的名字,完成枚举类型的定义后,我们可以用它作为数据类型来定义变量;而在枚举类型的定义中,可以逐个列出这个枚举类型的所有可能值。例如,可以将描述交通灯颜色的数据抽象成一个枚举类型:

// 交通灯颜色
enum TrafficLight
{
RED, // 红
GERRN, // 绿
YELLOW // 黄
};

有了这样的TrafficLight枚举类型的定义,我们就可以用它做为数据类型来定义一个变量,用以表示交通灯的颜色:

// 定义一个变量light表示交通灯的颜色
// 将枚举值RED赋值给它,表示当前交通灯是红色
TrafficLight light = RED;

因为枚举类型所表达数据的特殊性,使我们在应用枚举类型时需要注意以下几点。

1. 枚举类型中的枚举值有对应的默认整数值

在本质上,枚举类型数据是一个整型数值,每个枚举类型的可选值其实是一个整数值。在默认情况下,第一个枚举值对应的是整数值0,第二个是1,以此类推。例如,上面TrafficLight枚举类型中的RED可选值其实就是整数值0,而GREEN就是1,YELLOW自然就是2了。如果认为枚举值的默认对应整数值不合适。比如,在某些情况下,我们希望某个枚举值拥有特殊的整数值以表示特殊含义,这时也可以在定义的时候另行指定各个枚举值对应的整数值。例如:

// 另行指定各个枚举值对应的整数值
enum TrafficLight
{
RED = , // 指定对应的整数值,不再是从0开始
GERRN, //
YELLOW = // 指定对应的整数值为0,表示特殊含义
};

经过人为地指定枚举值对应的数值后,RED对应的整数值就变为了1,其后的GREEN增加一个自然也就随之而变为2,而对于最后的YELLOW,因为其特殊意义,我们又人为地将其指定为0。

2. 枚举类型变量的赋值

如果变量是枚举类型,那就只能使用这种枚举类型的某个枚举值对其进行赋值。例如:

// 红灯
TrafficLight light = RED;
// 变为绿灯
light = GREEN;
// 如果是用枚举值之外的数据对其进行赋值,会导致编译错误
// 即使这个值是某个枚举值对应的整数值
light = ;

换句话说,如果想把某个变量的取值限定在某几个可选值范围之内,则可以把这个变量定义为枚举类型变量。

3. 枚举值是常量,定义后不可改变其对应整数值

在定义枚举类型时,就已经完成了枚举值的定义,其对应的数值不是默认数值就是给定的特殊数值。定义完成后,各个枚举值的数值就成为了常量,要按照常量来处理,不能对其进行赋值。也就是说,不能在完成定义后再改变其中某个枚举值对应的整数值。例如,下面的语句是非法的:

RED = ;  // 尝试改变枚举值,导致编译错误

枚举类型中的枚举值实质是一些整型常量。在上面的例子中,完全可以使用3个整型常量来表示交通灯的三种颜色。但是,枚举类型允许我们用描述性的名称来表示某个有限范围内的整数值,而不是直接使用含义模糊的整数值,这有助于确保给变量指定合法的期望值,同时这也使得我们的代码意义明确,更具可读性,也更易于维护。所以,如果要表达的数据“只有有限的几种可能值”时,我们应该优先选择使用枚举类型。

知道更多:带作用域的枚举类

虽然枚举类型可以方便地定义某个范围内的枚举值。但是,因为传统的枚举类型在本质上是一个int类型的整数,因此在使用中,也常常存在各种各样的问题。例如,传统枚举类型的所有枚举值在其定义后的代码范围内都是可以使用的,而这可能会造成名字污染,使得其后的代码就不能再把这个枚举值名字用作其他用途;不可以指定枚举类型的底层数据类型,这可能会浪费内存资源,同时也使得枚举类型不可以进行前向声明。所谓前向声明,就是在某个元素(函数或者类)尚未定义的时候,为了提前使用它而进行的声明,向编译器表明源文件中有这个元素的定义,现在就可以放心大胆地使用,而具体的定义会在稍后给出。正是为了解决传统枚举类型所存在的这些问题,C++11提出了新的具有作用域,并可以指定底层数据类型的枚举类。

定义枚举类的语法形式跟定义一个传统的枚举类型的语法形式十分相似:

enum class 枚举类名:数据类型
{
// 可能的枚举值列表
};

枚举类的定义以“enum class”开始,后面跟上枚举类名,其后还可以用冒号“:”指定枚举类的底层数据类型。枚举类的底层数据类型必须是有符号或无符号的整型数,如果不指定,其默认的数据类型是int类型。例如:

// 定义一个枚举类TrafficLight,
// 并指定其底层数据类型为char类型
enum class TrafficLight : char
{
RED = , // 红
GERRN, // 绿
YELLOW // 黄
};

虽然枚举类的定义同传统的枚举类型的定义十分相似,但是因为两者内在机制的不同,他们已经是完全不同的两个概念。枚举类具有作用域,其枚举值只在其作用域内可见,这就很好地解决了枚举值可能引起的名字污染问题。例如:

// 枚举值RED属于TrafficLight作用域
// 所以我们必须在其前面加上TrafficLight才能访问
TrafficLight light = TrafficLight::RED;
// 定义一个名为RED的变量,虽然与枚举值RED同名,
// 但是两者不会产生冲突,也就是枚举值RED的定义
// 没有引起名字污染
bool RED = true;

除了解决名字污染问题之外,因为可以指定枚举的底层数据类型,这使得前向声明成为可能,同时,根据枚举值的多少,选择合适的底层数据类型,也可以在一定程度上避免资源的浪费。例如:

// 使用前的前向声明,只是声明了枚举类的名字,
// 没有定义具体的枚举值
enum class TrafficLight : char;
// 使用前向声明的枚举类
void foo(TrafficLight* light)
{
// ...
} // … // 补充完成枚举类的定义
enum class TrafficLight : char
{
RED = , // 红
// …
};

在这段代码中,我们完成枚举类TrafficLight枚举类的前向声明后,就可以直接使用了。而在最后,我们只需要补充上它的具体定义即可。另外,我们在这里指定了枚举值的底层数据类型为char,这要比默认的int更加节省资源。

从上面的例子我们可以看到,枚举类的使用,很好地解决了传统的枚举类型在使用中所遇到的各种问题,所以,在以后的编程实践中,我们应该优先选择使用枚举类。

你好,C++(13)这道单选题的答案是A、B、C还是D?3.7 枚举类型的更多相关文章

  1. 某软件大赛C#版考题整理——【单选题】

    多选题:http://www.cnblogs.com/zxlovenet/p/3525849.html 编程题:http://www.cnblogs.com/zxlovenet/p/3525854.h ...

  2. h5 页面 实现单选题,多选题功能。

    效果图: 项目要求: 1:实现单选题和多选题区分 (这个根据后端传来的数据判断 ) 2 单选选中效果 和  多选选中效果(利用input 和label ) 3.答题成功与失败 分单选和多选的情况    ...

  3. 华为云Stack首席架构师:打造“称手”的数字化工具,答好政企IT数字化转型这道必选题

    摘要:数字化转型是一号位工程,数字化的工具本身就是企业的核心竞争力. 本文分享自华为云社区<华为云Stack首席架构师:打造"称手"的数字化工具,答好政企IT数字化转型这道必 ...

  4. html5--3.13 表单的新增属性

    html5--3.13 表单的新增属性 学习要点 掌握表单新增属性的使用 HTML5新增表单属性 之前课程中已经接触过的新增属性:autocomplete属性/autofocus属性/list属性/m ...

  5. K2 BPM_“选BPM还是RPA?”,这不是一道单选题_全业务流程管理专家

    在我们和企业讨论流程自动化的时候,经常会被问到一个问题,“公司目前正在调研市面上的业务流程自动化产品,我们已经把选择范围缩小到了BPM和RPA之间.我们应该怎么选择?BPM能做的好像RPA都能做到.” ...

  6. 用私有构造器或者枚举类型强化SingleTon(单例)属性

    单例(singleton)就是一个只实例化一次的类.使类成为单例可能会使它的测试变得困难,因为除非它实现了作为其类型的接口,否则不可能用模拟实现来代替这个单例.下面是几种实现单例的方法: 1.共有静态 ...

  7. Effective Java —— 用私有构造器或枚举类型强化单例属性

    本文参考 本篇文章参考自<Effective Java>第三版第三条"Enforce the singleton property with a private construc ...

  8. Django ORM 操作 必知必会13条 单表查询

    ORM 操作 必知必会13条 import os # if __name__ == '__main__': # 当前文件下执行 os.environ.setdefault('DJANGO_SETTIN ...

  9. Nodejs in Visual Studio Code 13.构建单页应用Scrat示例挖一挖

    1.开始 Scrat作者说要搞个很碉堡的示例,果然就搞出来了,如果要学习并使用Scrat,可以从官方示例开始,简直太方便了. 2.Scrat示例 目录 component_modules : 公共组件 ...

随机推荐

  1. windows+linux下jdk安装及java环境变量配置

    对于初学java的用户来说,可能第一件要做的事情就是安装jdk及配置环境,以下内容主要讲述windows及linux下jdk的安装以及环境变量的配置. 1.首先下载相应平台可用版本jdk安装文件,可以 ...

  2. 关于泥水佬的minihttp与MVC4的对比

    相同的功能: 在Action里面实现调用Redis服务端的时间戳,然后转成“yyyy-MM-dd HH:mm:ss”格式的字符串,显示在界面上,显示结果是一样的: 下面分别贴上用ab压的结果: 先是M ...

  3. Prime邻接表+优先队列

    #include <iostream> #include <cmath> #include <cstring> #include <cstdlib> # ...

  4. 【规律】【贪心】【数学】HDU 5573 Binary Tree

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5573 题目大意: 从1走到第k层,下一层的数是上一层的数*2或者*2+1,可以选择加上或者减去走的数 ...

  5. HDOJ(HDU) 1799 循环多少次?(另类杨辉三角)

    Problem Description 我们知道,在编程中,我们时常需要考虑到时间复杂度,特别是对于循环的部分.例如, 如果代码中出现 for(i=1;i<=n;i++) OP ; 那么做了n次 ...

  6. Android新浪微博客户端(四)——添加多个账户及认证

    原文出自:方杰| http://fangjie.info/?p=75转载请注明出处 二.获取用户信息并保存数据库 上面说到加载AuthActivity有两种情况,其中一种就是授权成功回调,在授权回调成 ...

  7. mysql数据库sql常用命令

    1.查看索引:mysql> show index from tblname; 2.利用索引查询:SELECT * FROM product WHERE ID > =(select id f ...

  8. yii2使用Gii生成代码

    本章节将介绍怎样使用 Gii 去自己主动生成 Web 网站经常使用功能的代码.使用 Gii 生成代码很easy,仅仅要依照 Gii 页面上的介绍输入正确的信息就可以. 贯穿本章节,你将会学到: 在你的 ...

  9. android自定义倒计时控件示例

    这篇文章主要介绍了Android秒杀倒计时自定义TextView示例,大家参考使用吧 自定义TextView控件TimeTextView代码: 复制代码 代码如下: import android.co ...

  10. android listview综合使用演示样例_结合数据库操作和listitem单击长按等事件处理

    本演示样例说明: 1.自己定义listview条目样式,自己定义listview显示列数的多少,灵活与数据库中字段绑定. 2.实现对DB的增删改查,而且操作后listview自己主动刷新. 3.响应用 ...