深入现代 C++:enum class 全面解析,彻底告别枚举踩坑!

深入现代 C++:enum class 全面解析,彻底告别枚举踩坑!

本篇摘要

  • 在 C++11 中引入了 枚举类(enum class),它是对传统 enum 的现代化改进,解决了传统枚举的多个问题,如命名冲突、隐式类型转换、作用域污染等。
在这里插入图片描述

一·传统枚举

如:

enumColor{ RED, GREEN, BLUE };enumLight{ RED,// 编译错误!命名冲突 YELLOW };
  • 我们会发现枚举的成员有冲突,因此会导致下面编译的报错:
在这里插入图片描述

传统 enum 存在的问题:

  • 命名冲突:不同枚举之间不能有相同的名字:

就是这个例子:

在这里插入图片描述
  • 作用域污染:枚举值暴露在全局或当前命名空间:

比如这里我们可以直接通过外接访问到这个成员:

在这里插入图片描述
  • 隐式转换:枚举值可以自动转换为 int
在这里插入图片描述

下面我们运行下:

root@hcss-ecs-7d13:/home/sw/linux_learn/extra_knowledge/enum_class# ./a.out0

发现结果就是0,明显自动隐式转换了。

  • 安全性差:容易误用、类型不安全。

这里就是我们上面暴露的问题的总结了,因此下面我们引入了C++的枚举类!

二·C++的枚举类

首先总结下它的特点,也就是对上面缺点的修正:

特性说明
作用域隔离枚举值只能通过 枚举类名::值 访问
类型安全不允许隐式转换为 int
可指定底层类型可控制枚举值的存储大小
可读性高代码结构清晰,易于维护

具体用法剖析

一般形式(当然我们一般默认成员都显转int,因此底层类型一般不写):

enumclass 枚举类名 [: 底层类型]{ 枚举值1, 枚举值2,...};

简单使用

比如还是那上面我们那个例子说明:

enumclassColor{ Red, Green, Blue };enumclassLight:uint32_t{ Red, Yellow };
  • 此时再编译就不会报错了!

此时我们需要突破类域方式去访问了:

在这里插入图片描述

运行结果:

root@hcss-ecs-7d13:/home/sw/linux_learn/extra_knowledge/enum_class# ./a.out Color is Red 

枚举类的底层类型Underlying Type

enumclassColor:uint8_t{ Red, Green, Blue };
  • 每个成员8个比特,理论这个枚举类大小就是1字节,下面验证下:

sizeof(Color) 后结果:

在这里插入图片描述

常见底层类型:

  • int(默认)
  • uint8_t / int8_t
  • uint16_t / int16_t
  • uint32_t / int32_t
  • uint64_t / int64_t

枚举类与整数的转换

由于 enum class 不允许隐式转换,必须显式转换。

只能:

static_cast<int>(c);

下面来验证下:

enumclassColor:uint8_t{ Red, Green, Blue };
Color c = Color::Green;int value =static_cast<int>(c); std::cout << value << std::endl;

结果符合预期:

在这里插入图片描述

但是要是反过来呢?

Color c2 =static_cast<Color>(2);
  • 不建议这样使用,如果整数不在枚举范围内,行为是未定义的。

最后一个特点就明显不用说了吧!

枚举类作为函数参数和返回值

作为函数参数

voidsetColor(Color c){ std::cout <<"Setting color to: "<<static_cast<int>(c)<< std::endl;}

输出:

在这里插入图片描述

作为函数返回值

Color getFavoriteColor(){return Color::Blue;}

这里如果我们强转成对应的类型uint8_t 此时就是这样:

 std::cout<<static_cast<uint8_t>(favorite)<<std::endl;

结果:

在这里插入图片描述
  • 我们发现它是空白其实,因为这杯cout把2转义成char类型,也就是整数2对应的ASIIC码: STX(Start of Text),它是不可见的,所以我们打印出来看不到!

因此需要:

 std::cout<<static_cast<int>(favorite)<<std::endl;

就如下:

在这里插入图片描述

拓展使用

结合switch进行转义选择使用

也就是我们通过对枚举成员进行switch操作,对指定枚举量安排指定操作(其他操作功能可自行拓展):

简单版如下:

enumclassColor:uint8_t{ Red, Green, Blue };voidprintColor(Color c){switch(c){case Color::Red: std::cout <<"Color: Red\n";break;case Color::Green: std::cout <<"Color: Green\n";break;case Color::Blue: std::cout <<"Color: Blue\n";break;default: std::cout <<"Unknown color\n";}}

下面我们测试一下:

在这里插入图片描述

获取枚举类的底层类型

  • 使用 <type_traits> 中的 std::underlying_type 可以获取枚举类的底层类型。

下面我们测试下:

代码:

#include<iostream>#include<type_traits>enumclassLevelType:uint16_t{ UNKNOW =0, DEBUG, INFO, WARN, ERROR };intmain(){using underlying_type = std::underlying_type<LevelType>::type; std::cout <<"Underlying type size: "<<sizeof(underlying_type)<<" bytes\n";return0;}

结果如下:

在这里插入图片描述
  • 符合预期!

封装枚举类:添加描述和状态码

  • 虽然 enum class 提供了类型安全和作用域隔离的优势,但它本身不支持直接附加描述信息或状态码。因此,我们常常需要通过类封装的方式,为枚举类添加描述、状态码、转换函数等功能。

首先要知道和之前的普通枚举一样是可以类内自己给值的:

enumclassCode{ OK=200, NotFound=404, InternalServerError=500};

但是下面我们通过封装类及提供接口方式来完成对应的设置获取等:

基于上述测试代码:

#include<iostream>#include<string>classHttpStatus{public:enumclassCode{ OK, NotFound, InternalServerError };explicitHttpStatus(Code code):code_(code){}// 获取状态码数值intgetStatusCode()const{switch(code_){case Code::OK:return200;case Code::NotFound:return404;case Code::InternalServerError:return500;}return-1;// 不应到达}// 获取状态描述 std::string getDescription()const{switch(code_){case Code::OK:return"OK";case Code::NotFound:return"Not Found";case Code::InternalServerError:return"Internal Server Error";}return"Unknown Status";}// 打印状态信息voidprint()const{ std::cout <<getStatusCode()<<" "<<getDescription()<< std::endl;}private: Code code_;};intmain(){ HttpStatus ok(HttpStatus::Code::OK); HttpStatus notFound(HttpStatus::Code::NotFound); HttpStatus serverError(HttpStatus::Code::InternalServerError); ok.print(); notFound.print(); serverError.print();return0;}
  • 运行后可以发现:
在这里插入图片描述
  • 这里就是我们通过对应的枚举成员码通过Switch进行对应的数字和描述的选择(也是常用作对应的比如http等)

通过类封装,我们可以为枚举类添加描述、状态码、转换方法等高级功能,同时在 switch 中显式处理所有枚举值,确保逻辑完整性和代码健壮性。

总结

一句话:

C++ 枚举类(enum class)是现代 C++ 编程中推荐使用的枚举形式,它解决了传统枚举的诸多问题,提高了代码的安全性、可读性和可维护性。

下面博主准备了关于它使用的顺口溜,帮助大家记忆:

枚举类,C++11,命名不冲突,作用域严。enum class 加限定,Red要加Color::才安全。隐式转换不允许,int转它要static_cast显。底层类型可指定,uint8_t省空间,嵌入式欢。switch要全覆盖,case别漏防出错,default保平安。封装功能更强大,加描述、状态码,类来管。类型安全最重要,enum class替旧版,代码稳!

传统枚举与枚举类对比:

特性传统 enum枚举类 enum class
命名冲突容易发生不会发生(作用域隔离)
隐式转换允许不允许
作用域枚举值暴露在外部枚举值只在类内部可见
可读性较差更清晰、更安全
底层类型不可指定支持指定(如 int, char

可视化流程图:

在这里插入图片描述

本篇分享枚举类使用知识到这里,欢迎大家继续订阅本专栏学习更多知识来充实大脑。

Read more

GCC 14编译选项配置实战(高性能C++构建秘籍)

第一章:GCC 14编译器的新特性与构建环境准备 GCC 14作为GNU编译器集合的最新稳定版本,引入了多项增强功能,显著提升了C++标准支持、诊断能力以及优化性能。开发者在使用前需确保构建环境满足最低依赖要求,并正确配置工具链。 核心新特性概览 * 全面支持C++23关键特性,包括std::expected和模板参数冗余推导 * 增强静态分析能力,新增对未定义行为的深度检测机制 * 优化跨函数边界内联策略,提升生成代码的执行效率 * 引入更精准的调试信息格式(DWARF-5),改善GDB调试体验 构建环境搭建步骤 在主流Linux发行版中安装GCC 14,推荐通过官方源或自定义编译方式获取: # 添加Ubuntu Toolchain PPA并安装 sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt update sudo apt install gcc-14 g++-14 # 设置默认编译器版本 sudo update-alternatives --install /usr/bin/

By Ne0inhk
【C++】B2108 图像模糊处理

【C++】B2108 图像模糊处理

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳]本文专栏: C++ 文章目录 * 💯前言 * 💯题目描述 * 题目内容 * 输入格式 * 输出格式 * 示例 * 输入: * 输出: * 💯题目分析 * 问题拆解 * 💯我的做法 * 代码实现 * 代码分析 * 💯老师的做法 * 代码实现 * 代码分析 * 💯两种实现的对比 * 💯相关概念拓展 * 1. 四舍五入的实现 * 2. 二维数组的边界处理 * 💯优化建议 * 💯小结 💯前言 在C++程序设计学习中,处理二维数组与图像问题是一个重要的实践内容,能够帮助我们熟悉矩阵操作、边界条件处理以及浮点运算等核心技能。本篇文章将以一个图像模糊处理的题目为切入点,详细剖析题目背景、解题思路与两种代码实现(我的做法与老师的代码),并对两者进行深入比较与优化。同时,还将补充相关概念的详细解析,以期让读者对问题有全面而深入的理解。 C++ 参考手册 💯题目描述 题目来源于一个二维矩阵的图像模糊处理问题,其具体要求如下

By Ne0inhk

基于MISRA C++的车载软件开发实战案例

车载C++为何必须“自我约束”?一个电机控制项目的MISRA实战手记 你有没有想过,为什么在性能越来越强的车载芯片上,工程师反而要主动放弃C++里那些炫酷的功能? 比如异常处理、动态内存分配、宏函数、多重继承……这些在普通软件开发中习以为常的特性,在车规级代码里却成了“禁区”。这不是技术倒退,而是一场为了 安全与确定性 的必要妥协。 最近我参与了一个新能源车永磁同步电机控制器(PMSM)的软件开发项目,运行平台是英飞凌AURIX TC3xx系列多核MCU,系统等级达到ASIL-D——功能安全的最高级别。在这个项目中,我们不仅要用C++写高效控制算法,还得让每一行代码都经得起第三方审计的拷问。 最终的答案很明确: MISRA C++:2008 。 这不是一套可有可无的编码风格指南,而是整个软件生命周期中的“法律条文”。它不教你如何实现FOC算法,但它确保你的算法不会因为一个未初始化变量或一次非法指针访问而导致整车失控。 下面,我就以这个真实项目为背景,带你走进MISRA C++的实战世界——不是照本宣科地念规则,而是告诉你: 为什么非得这么做?不这么做会出什么事?我们又是怎么

By Ne0inhk
【C/C++刷题集】string类(一)

【C/C++刷题集】string类(一)

🫧个人主页:小年糕是糕手 💫个人专栏:《C++》《Linux》《数据结构》《C语言》 🎨你不能左右天气,但你可以改变心情;你不能改变过去,但你可以决定未来! 目录 一、字符串最后一个单词的长度 二、验证回文串 三、字符串中的第一个唯一字符 四、反转字符串 一、字符串最后一个单词的长度 字符串最后一个单词的长度 这里我们看题目有一个注意点就是我们平常使用cin输入时遇到空格会停下来,在例子中我们可以看到他有A B C D,如果我们使用cin在遇到第一个A之后就会报错,所以这里我们要用到另一种输入方式:getline 他并不是一个成员函数,而是输入流的全局函数 getline(istream&, string&)(定义在 <string> 头文件中),作用是从输入流中读取一整行内容,存入 string 对象。 // 基础用法(读整行) getline(

By Ne0inhk