枚举类与强类型
本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 80 课,共 104 课。
C++11 引入了枚举类(也称为作用域枚举),用于解决传统 C 风格枚举的不足。它们提供了更强的类型安全性,并能防止意外误用枚举值。
传统枚举存在一些问题:枚举值会泄漏到外围作用域,并且会隐式转换为整数,从而导致难以察觉的 bug:
// 传统的 enum:有问题
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green }; // 错误!Red 和 Green 已经定义过了
int x = Red; // 隐式转换为 int(0)
if (Red == 0) { } // 可以编译:将 enum 与 int 比较枚举类通过限定值的作用域并阻止隐式转换,解决了这些问题:
enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green }; // 可以,没有冲突
Color c = Color::Red; // 必须使用作用域运算符
// int x = c; // 错误!不能隐式转换
int x = static_cast<int>(c); // 需要显式转换
// if (c == 0) { } // 错误!不能与 int 比较
if (c == Color::Red) { } // 可以,比较的是相同类型你还可以指定底层类型来控制内存:
enum class Status : uint8_t {
Inactive = 0,
Active = 1,
Pending = 2
};枚举类与面向对象编程(OOP)设计结合得很好,能让代码更易读,并在编译时而不是运行时捕获类型错误。
挑战
简单让我们构建一个任务优先级系统,使用枚举类表示不同的优先级和任务状态。这能展示枚举类如何提供类型安全,并防止传统枚举可能导致的错误。
你将把代码分到 3 个文件中:
TaskTypes.h:为任务系统定义枚举类。创建一个
Priority枚举类,包含以下值:Low、Medium、High和Critical。指定int为底层类型,值分别为 1、2、3 和 4。创建一个
Status枚举类,包含以下值:Pending、InProgress和Completed。提供两个辅助函数:
priorityToString(Priority p):将优先级转换为字符串("Low"、"Medium"、"High" 或 "Critical")statusToString(Status s):将状态转换为字符串("Pending"、"InProgress" 或 "Completed")
Task.h:定义一个使用这些枚举类的Task类。你的
Task应存储名称(字符串)、Priority和Status。构造函数应接收名称和优先级,状态默认设为Status::Pending。实现以下方法:
setStatus(Status s):更新任务状态getPriorityValue():使用static_cast返回优先级的底层整数值display():按以下格式输出任务:[name] - Priority: [priority] (Value: [value]) - Status: [status]
main.cpp:读取 3 个输入:- 任务名称(字符串)
- 优先级(整数,1=Low,2=Medium,3=High,4=Critical)
- 状态(整数,0=Pending,1=InProgress,2=Completed)
使用给定的名称和优先级创建一个
Task(使用static_cast将整数转换为相应的Priority枚举值)。然后根据第三个输入设置任务状态。最后,调用display()显示任务详情。
例如,输入 Fix bug、3 和 1 时:
Fix bug - Priority: High (Value: 3) - Status: InProgress输入 Write docs、1 和 2 时:
Write docs - Priority: Low (Value: 1) - Status: Completed输入 Deploy app、4 和 0 时:
Deploy app - Priority: Critical (Value: 4) - Status: Pending注意,枚举类会让优先级和状态值完全分开。你不能意外地将 Priority 与 Status 进行比较,也不能把其中一个赋给另一个。整数和枚举值之间的转换必须显式使用 static_cast,这能让代码的意图更加清楚,并防止细微错误。
亲手试试
#include <iostream>
#include <string>
#include "Task.h"
using namespace std;
int main() {
// 读取输入
string taskName;
int priorityInt;
int statusInt;
getline(cin, taskName);
cin >> priorityInt;
cin >> statusInt;
// TODO: 用给定的名称和优先级创建一个 Task
// 使用 static_cast 将 priorityInt 转换为 Priority 枚举类型
// TODO: 根据 statusInt 设置任务的状态
// 使用 static_cast 将 statusInt 转换为 Status 枚举类型
// TODO: 调用 display() 显示任务详情
return 0;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C++ 在线编译器