018 C++的枚举类型(enum和enum class)


作者Lou Xiao, deepseek创建时间2025-04-02 15:04:00更新时间2025-04-02 15:04:00

1. 传统枚举(enum)

1.1 基本概念

  • 传统枚举是C++从C语言继承的特性
  • 定义方式:enum 枚举名 {枚举值列表};
  • 枚举值默认从0开始,依次递增

1.2 基本语法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 enum Color {
2 RED, // 0
3 GREEN, // 1
4 BLUE // 2
5 };
6
7 Color c = RED;

1.3 特性

  • 隐式转换:枚举值可隐式转换为整数
  • 作用域污染:枚举值暴露在包含枚举定义的作用域中
  • 类型不安全:不同枚举类型之间可以比较
  • 可指定值:可以显式为枚举值指定整数值
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 enum HttpCode {
2 OK = 200,
3 NOT_FOUND = 404,
4 SERVER_ERROR = 500
5 };

1.4 局限性

  • 不同枚举类型之间可以比较(类型不安全)
  • 枚举值会污染所在作用域
  • 无法指定底层类型(C++11前)

2. 枚举类(enum class)

2.1 基本概念

  • C++11引入的新特性
  • 定义方式:enum class 枚举名 {枚举值列表};
  • 强类型枚举,解决传统枚举的问题

2.2 基本语法

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 enum class Color {
2 RED,
3 GREEN,
4 BLUE
5 };
6
7 Color c = Color::RED;

2.3 特性

  • 强类型:不会隐式转换为整数
  • 作用域限定:枚举值必须通过枚举名访问
  • 类型安全:不同枚举类型不能比较
  • 可指定底层类型:可以显式指定底层存储类型
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 enum class Color : uint8_t {
2 RED = 1,
3 GREEN = 2,
4 BLUE = 3
5 };

2.4 优势

  1. 避免命名冲突
  2. 提高类型安全性
  3. 可控制底层类型
  4. 更符合现代C++的设计理念

3. 对比总结

特性enumenum class
作用域污染外层作用域限定在枚举内部
隐式转换允许不允许
类型安全
底层类型指定C++11后支持支持
访问方式直接访问必须加枚举名限定
前向声明需要完整定义可直接声明

4. 使用建议

  1. 优先使用enum class:除非需要与旧代码兼容,否则应优先使用enum class
  2. 指定底层类型:当需要控制枚举的大小时,显式指定底层类型
  3. 避免隐式转换:即使使用传统enum,也应避免依赖隐式转换
  4. 考虑可读性:为枚举值使用有意义的名称

5. 高级用法

5.1 位标志枚举

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 enum class FilePermissions : uint8_t {
2 READ = 1,
3 WRITE = 2,
4 EXECUTE = 4
5 };
6
7 FilePermissions perms = FilePermissions::READ | FilePermissions::WRITE;

5.2 枚举与switch语句

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 enum class Status {
2 SUCCESS,
3 FAILURE,
4 PENDING
5 };
6
7 void handleStatus(Status s) {
8 switch(s) {
9 case Status::SUCCESS: /*...*/ break;
10 case Status::FAILURE: /*...*/ break;
11 case Status::PENDING: /*...*/ break;
12 }
13 }

5.3 枚举与运算符重载

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 enum class Day {
2 MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
3 };
4
5 Day& operator++(Day& d) {
6 d = static_cast<Day>((static_cast<int>(d) + 1) % 7);
7 return d;
8 }

6. 最佳实践

  1. 命名规范:使用大写字母和下划线命名枚举值(如Color::RED
  2. 相关操作封装:将与枚举相关的操作封装为函数
  3. 避免魔数:使用枚举代替硬编码的数字
  4. 文档注释:为枚举添加注释说明其用途和各个值的含义

7. 常见问题与解决方案

7.1 如何遍历枚举值?

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 enum class Color { RED, GREEN, BLUE, COUNT };
2
3 for (int i = 0; i < static_cast<int>(Color::COUNT); ++i) {
4 Color c = static_cast<Color>(i);
5 // 使用c
6 }

7.2 如何将enum转换为字符串?

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 const char* ColorToString(Color c) {
2 switch(c) {
3 case Color::RED: return "RED";
4 case Color::GREEN: return "GREEN";
5 case Color::BLUE: return "BLUE";
6 default: return "UNKNOWN";
7 }
8 }

7.3 如何将字符串转换为enum?

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 Color StringToColor(const std::string& s) {
2 if (s == "RED") return Color::RED;
3 if (s == "GREEN") return Color::GREEN;
4 if (s == "BLUE") return Color::BLUE;
5 throw std::invalid_argument("Invalid color string");
6 }

8. C++20增强

C++20为枚举添加了更多特性:
- 使用using enum引入枚举值到当前作用域
- 简化枚举值的访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 enum class Color { RED, GREEN, BLUE };
2
3 void foo() {
4 using enum Color; // C++20特性
5 Color c = RED; // 无需Color::前缀
6 }
文章目录