C++枚举类型

枚举类型

枚举类型使我们可以将一组整型常量组织在一起。

和类一样,每个枚举类型定义了一种新的类型。

枚举属于字面值常量类型。

C++包含两种枚举:限定作用域的和不限定作用域的。

限定作用域的枚举类型

C++11新标准引入了限定作用域的枚举类型。

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

enum class open_modes (input, output, append);


我们定义了一个名为open_modes的枚举类型,它包含三个枚举成员:input、output和append。

不限定作用域的枚举类型

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

enum color(red,yellow, green); // 不限定作用域的枚举类型

//未命名的、不限定作用域的枚举类型
enum(floatPrec=6, doublePrec = 10, double_doublePrec = 10};

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

枚举成员

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

我们来看看容易用错的几个点子

易错点1:重复定义枚举成员

不限定作用域的枚举类型

enum A { a, b, c };
enum B { a, b, c };//重复定义枚举成员

 

这是因为在不限定作用域的枚举类型中,枚举成员的作用域与枚举类型本身的作用域相同

限定作用域的枚举类型

相反,在限定作用域的枚举类型中就不会出现这种问题

	enum class A { a, b, c };
	enum class B { a, b, c };//没有问题

这是因为枚举成员的作用域仅限于其对应的枚举类型,对外界是不可见的

所以我们可以混用不限定作用域的枚举类型和限定作用域的枚举类型

enum  A { a, b, c };
enum class B { a, b, c };//没有问题

易错点2:给枚举类型赋值

限定作用域的枚举类型

enum class B { a, b, c };
B b1 = a;//会报错
B b2 = B::a;//没有问题

我们不能在枚举类型定义外直接使用限定作用域的枚举类型的枚举成员,必须通过::来显式访问 

不限定作用域的枚举类型

enum A{a,b,c};
A a1 = a;//正确
A a2 = A::a;//正确

我们可以通过两种方式来使用不限定作用域的枚举类型的枚举成员。 

混用两种枚举类型

enum  A { a, b, c };
enum class B { a, b, c };//没有问题

A a1 = a;//没有问题,因为
B b1 = a;//有问题,因为B类型的b成员的作用域被限定在枚举类型中,
//所以此时赋给b1的是A::a,而不是B::a

A a2 = A::a;//没有问题
B b2 = B::a;//没有问题

就自己看吧

枚举成员的值

默认情况下,枚举值从0开始,依次加1。

enum A{a,b,c};
//默认a=0,b=1,c=2

不过我们也能为一个或几个枚举成员指定专门的值:

enum class_intTypes{
charTyp = 8, shortTyp = 16, intTyp = 16, 
longTyp = 32, long_longTyp = 64
}

由枚举成员 intTyp和shortTyp可知,枚举值不一定唯一。

如果我们没有显式地提供初始值,则当前枚举成员的值等于之前枚举成员的值加1。

enum A{a=9,b=3,c};//默认c的值是它前面的那个成员的值加一,也就是4

枚举成员是const

枚举成员是const,因此在初始化枚举成员时提供的初始值必须是常量表达式。

也就是说,每个枚举成员本身就是一条常量表达式,我们可以在任何需要常量表达式的地方使用枚举成员。

例如,我们可以定义枚举类型的constexpr变量:

enum A{a,b,c};
constexpr A a3= A::a;


类似的,我们也可以将一个enum作为switch语句的表达式,而将枚举值作为case标签

enum A{a,b,c};
 A a3= A::a;
 switch (a3)
 {
 case a:cout << "a" << endl; break;
 case b:cout << "b" << endl; break;
 case c:cout << "c" << endl; break;
}

出于同样的原因,我们还能将枚举类型作为一个非类型模板形参使用;

enum Color {
    RED,
    GREEN,
    BLUE
};

template<Color color>
class MyClass {
public:
    void printColor() {
        switch (color) {
            case RED:
                std::cout << "Red" << std::endl;
                break;
            case GREEN:
                std::cout << "Green" << std::endl;
                break;
            case BLUE:
                std::cout << "Blue" << std::endl;
                break;
        }
    }
};

int main() {
    MyClass<RED> redObj;
    redObj.printColor();  // 输出 "Red"

    MyClass<GREEN> greenObj;
    greenObj.printColor();  // 输出 "Green"

    return 0;
}

或者在类的定义中初始化枚举类型的静态数据成员。

class C
{
	enum  A { a, b, c };
	static int d[a] ;
	static const int e = b;
};

和类一样,枚举也定义新的类型

只要enum有名字,我们就能定义并初始化该类型的成员。

要想初始化enum对象或者为enum对象赋值,必须使用该类型的一个枚举成员或者该类型的另一个对象,

enum  A{a,b,c};
A a1 = A::a;//正确

一个不限定作用城的枚举类型的对象或枚举成员自动地转换成整型,限定作用域的枚举类型不会进行隐式转换

因此,我们可以在任何需要整型值的地方使用它们:

enum  A{a,b,c};
enum class B{d,e};
int a1 = a;//可以
int b1 = B::d;//不可以,限定作用域的枚举类型不会进行隐式转换

指定enum的大小

尽管每个enum都定义了唯一的类型,但实际上enum是由某种整数类型表示的。

在C++11新标准中,我们可以在enum的名字后加上冒号以及我们想在该enum中使用的类型:

enum intValues : unsigned long long {

charTyp = 255, shortTyp = 65535, intTyp = 65535, 
longTyp = 4294967295UL,
long_longTyp = 18446744073709551615ULL
};


如果我们没有指定enum的潜在类型,则默认情况下限定作用域的enum成员类型是int。

对于不限定作用域的枚举类型来说,其枚举成员不存在默认类型,我们只知道成员的潜在类型足够大,肯定能够容纳枚举值。

如果我们指定了枚举成员的潜在类型(包括对限定作用域的enum的隐式指定),则一旦某个枚举成员的值超出了该类型所能容纳的范围,将引发程序错误。

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

枚举类型的前置声明

在C++11 新标准中,我们可以提前声明 enum。

enum的前置声明(无论隐式地还是显示地)必须指定其成员的大小

//不限定作用域的枚举类型intValues的前置声明
enum A : unsigned long long;// 不限定作用域的,必须指定成员类型

enum class B; //限定作用域的枚举类型可以使用默认成员类型int
  1. 因为不限定作用域的enum未指定成员的默认大小,因此每个声明必须指定成员的大小,这里被指明为unsigned long long
  2. 对于限定作用域的enum来说,我们可以不指定其成员的大小,这个值被隐式地定义成int。

和其他声明语句一样,enum的声明和定义必须匹配,这意味着在该enum的所有声明和定义中成员的大小必须一致。

enum A : unsigned long long;

enum  A:long {a,b,c};//这是错误的


而且,我们不能在同一个上下文中先声明一个不限定作用域的enum名字,然后再声明一个同名的限定作用域的enum:
 

enum class intValues;// 错误:所有的声明和定义必须对该enum是限定作用域的还是不限定作用域的保持一致
enum intValues;// 错误:intValues已经被声明成限定作用域的

 enum intValues : long; //错误:intValues 已经被声明成int

形参匹配与枚举类型

要想初始化一个enum对象,必须使用该enum类型的另一个对象或者它的一个枚举
成员。

因此,即使某个整型值恰好与枚举成员的值相等,它也不能作为函数的enum实参使用:

//不限定作用域的枚举类型,潜在类型因机器而异
enum Tokens {INLINE = 128, VIRTUAL = 129};
void ff(Tokens);
void ff(int);

int main() {
Tokens curTok = INLINE;
ff(128); // 精确匹配 ff(int)
ff(INLINE) ;// 精确匹配 ff(Tokens)
ff(curTok); //精确匹配 ff(Tokens)
return 0;


尽管我们不能直接将整型值传给enum形参,但是可以将一个不限定作用域的枚举类型的对象或枚举成员传给整型形参。

此时,enum的值提升成int或更大的整型,实际提升的结果由枚举类型的潜在类型决定:

void newf (unsigned char);
void newf(int);
unsigned char uc = VIRTUAL;
newf(VIRTUAL); // 调用 newf(int)
newf(uc); // 调用 newf (unsigned char)


枚举类型 Tokens只有两个枚举成员,其中较大的那个值是129。该枚举类型可以用unsigned char来表示,因此很多编译器使用unsigned char作为Tokens的潜在类型。

不管Tokens的潜在类型到底是什么,它的对象和枚举成员都提升成int

尤其是,枚举成员永远不会提升成unsigned char,即使枚举值可以用unsigned char存储是如此。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/494654.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云实时计算Flink的产品化思考与实践【上】

摘要&#xff1a;本文整理自阿里云高级产品专家黄鹏程和阿里云技术专家陈婧敏在 FFA 2023 平台建设专场中的分享。内容主要为以下五部分&#xff1a; 阿里云实时计算 Flink 简介产品化思考产品化实践SQL 产品化思考及实践展望 该主题由黄鹏程和陈婧敏共同完成&#xff0c;前半程…

插入排序、归并排序、堆排序和快速排序的稳定性分析

插入排序、归并排序、堆排序和快速排序的稳定性分析 一、插入排序的稳定性二、归并排序的稳定性三、堆排序的稳定性四、快速排序的稳定性总结在计算机科学中,排序是将一组数据按照特定顺序进行排列的过程。排序算法的效率和稳定性是评价其优劣的两个重要指标。稳定性指的是在排…

【地图构建(1)】占用栅格地图构建Occupancy grid mapping

本文主要参考Probabilistic Robotics《概率机器人》一书。 其他参考&#xff1a; 弗莱堡大学课件 博客 含代码博客 0.引言 位姿已知的地图构建(mapping with known poses)的定义&#xff1a;已知机器人的位姿 x 1 : t x_{1:t} x1:t​和传感器的观测数据 z 1 : t z_{1:t} z1:t…

云原生(六)、CICD - Jenkins快速入门

Jenkuns快速入门 一、CICD概述 CICD是持续集成&#xff08;Continuous Integration&#xff09;和持续部署&#xff08;Continuous Deployment&#xff09;的缩写。它是软件开发中的一种流程和方法论&#xff0c;旨在通过自动化的方式频繁地将代码集成到共享存储库中&#xf…

zotero+word优化管理参考文献

写论文&#xff0c;整理参考文献&#xff0c;管理参考文献很麻烦&#xff0c;参考文献格式罗列很麻烦&#xff0c;论文需要修改时&#xff0c;重新调整参考文献顺序很麻烦。 zoteroword可以很好的帮助解决这个问题。 Step1 zotero软件安装 默认word你已经安装好了 step2 安…

线程局部存储(TLS)

线程局部存储&#xff08;Thread Local Storage&#xff0c;TLS&#xff09;&#xff0c;是一种变量的存储方法&#xff0c;这个变量在它所在的线程内是全局可访问的&#xff0c;但是不能被其他线程访问到&#xff0c;这样就保持了数据的线程独立性。而熟知的全局变量&#xff…

班级综合测评管理系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文&#xff08;设计&#xff09;学生选题参考合集推荐收藏&#xff08;包含Springboot、jsp、ssmvue等技术项目合集&#xff09; 目录 1. …

二十 超级数据查看器 讲解稿 功能概述

二十 超级数据查看器 讲解稿 功能概述 ​ ​​点击此处 以新页面 打开B站 播放当前教学视频 点击访问app下载页面 豌豆荚 下载地址​ ​ 讲解稿 ​ 界面启动 ​ 导入 ​ 选excel文件 导入 ​ 原来的excel文件 ​ 导入进本地数据库sqlite ​ 导入成功 ​ 列…

MySQL---事务

目录 一、事务简介 二、事务操作 1.未控制事务 2.事务控制一 3.控制事务二 三、事务的四大特性 四、并发事务问题 五、事务隔离级别 一、事务简介 事务 是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向系统提交或…

喜讯!聚铭网络荣获《日志分类方法及系统》发明专利

近日&#xff0c;聚铭网络又喜获一项殊荣&#xff0c;其申报的《日志分类方法及系统》发明专利成功获得国家知识产权局的授权&#xff0c;正式荣获国家发明专利证书。 在信息化时代&#xff0c;网络安全问题日益凸显&#xff0c;日志分析作为保障网络安全的重要手段&#xff…

【嵌入式——C语言】VScode编写C程序、交叉编译

【嵌入式——C语言】VScode编写C程序、交叉编译 第一步第二步第三步第四步第五步第六步第七步第八步 第一步 下载Visual Studio Code下载地址 然后直接安装就可以了。 第二步 前提是你的电脑上安装了WSL。。。 打开vscode的扩展&#xff0c;输入WSL进行安装 安装完之后在窗…

【深度学习】图片预处理,分辨出模糊图片

ref:https://pyimagesearch.com/2015/09/07/blur-detection-with-opencv/ 论文 ref:https://www.cse.cuhk.edu.hk/leojia/all_final_papers/blur_detect_cvpr08.pdf 遇到模糊的图片&#xff0c;还要处理一下&#xff0c;把它挑出来&#xff0c;要么修复&#xff0c;要么弃用。否…

vue组件如何使用?

今天我随便试两个组件 第一个轮播图 在minn.js 引入 import { createApp } from vue; import { Swipe, SwipeItem } from vant; const app createApp(); app.use(Swipe); app.use(SwipeItem); <van-swipe class"my-swipe" :autoplay"3000" indica…

uniapp 微信小程序 canvas 手写板文字重复倾斜水印

核心逻辑 先将坐标系中心点通过ctx.translate(canvasw / 2, canvash / 2) 平移到canvas 中心&#xff0c;再旋转设置水印 假如不 translate 直接旋转&#xff0c;则此时的旋转中心为左上角原点&#xff0c;此时旋转示意如图所示 当translate到中心点之后再旋转&#xff0c;此…

逐步学习Go-协程goroutine

参考&#xff1a;逐步学习Go-协程goroutine – FOF编程网 什么是线程&#xff1f; 简单来说线程就是现代操作系统使用CPU的基本单元。线程基本包括了线程ID&#xff0c;程序计数器&#xff0c;寄存器和线程栈。线程共享进程的代码区&#xff0c;数据区和操作系统的资源。 线…

每日一题--- 环形链表[力扣][Go]

环形链表 题目&#xff1a;142. 环形链表 II 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给…

数字身份的革命:解锁 Web3 的身份验证技术

引言 随着数字化时代的到来&#xff0c;个人身份认证成为了日常生活和商业活动中不可或缺的一部分。传统的身份验证方式存在着安全性低、易伪造、不便利等问题&#xff0c;因此&#xff0c;人们迫切需要一种更安全、更便捷的身份验证技术。在这样的背景下&#xff0c;Web3的身…

数仓建设实践——58用户画像数仓建设

目录 一、数据仓库&用户画像简介 1.1 数据仓库简介 1.2 数据仓库的价值 1.3 用户画像简介 1.4 用户画像—标签体系 二、用户画像数仓建设过程 2.1 画像数仓—背景&现状 2.2 画像数仓—整体架构 2.3 画像数仓—研发流程 2.4 画像数仓—指标定义 2.5 画像数仓…

Java基本数据结构(基于jdk11)

java中有很多数据类型&#xff0c;以下数据类型都出于java.util包下且日常经常使用的&#xff0c;先介绍一下接口&#xff0c;接口可以很快的了解到这个数据结构的特性。 接口 List: 有序队列&#xff0c;如&#xff1a;ArrayList、LinkedList Deque&#xff1a;双端队列&am…

视图的作用

目录 视图的作用 创建视图 为 scott 分配创建视图的权限 查询视图 复杂视图的创建 视图更新的限制问题 更新视图中数据的部门编号&#xff08;视图的存在条件&#xff09; 限制通过视图修改数据表内容 创建只读的视图 复杂视图创建 oracle从入门到总裁:​​​​​​h…