c++ 学习笔记之 enum 与enum class
·
文章目录
1、介绍
1.1 enum
传统枚举enum在C++98 标准中就存在,是一种未限域枚举:
enum Color {
RED,
GREEN,
BLUE
};
1.2 enum class
c++11引入限域枚举:
enum class Color {
RED,
GREEN,
BLUE
};
二、区别
2.1 命名空间污染问题
当我们声明一个 enum 时,其中的枚举常量会泄漏到外层作用域,这意味着在该作用域内不能再出现与枚举常量同名的标识符,否则会导致编译错误。
enum Color { RED, GREEN };
enum Light { RED }; // 错误!重定义
即使两个枚举被定义在不同的头文件中,只要被一个文件同时引用,也会出现冲突,甚至枚举常量会和函数名出现冲突:
enum Color { RED, GREEN, BLUE };
void RED() {// 编译错误:与枚举值冲突
int aaa = 255;
}
C++11引入的enum class彻底解决了上述问题:
enum class Color { RED, GREEN };
enum class Light { RED}; // 正确
Color c = Color::RED; // 必须使用作用域限定
enum class对枚举常量的作用域进行了限定,枚举常量仅在其所属的枚举类型作用域内有效,但必须通过作用域限定符::才能访问。
2.2 类型安全问题
enum 类型不安全,它允许枚举常量隐式转换为整数类型,同时也允许不同枚举类型的常量之间进行比较,这可能会导致一些隐藏的 bug。
// enum的隐式转换问题
enum A{
RED,
GREEN,
BLUE
};
enum B{
APPLE,
BANANA
};
// 枚举常量隐式转换为int
int value= RED; // 正确,low被隐式转换为0
// 枚举常量与其他数值比较
if (GREEN== 1) { // 正确,medium隐式转换为1后比较
// ...
}
// 参数传递错误不会被编译器检测
void process(A a, B b) {
// ...
}
int main() {
A a = BLUE;
B b = BANANA;
process(b, a); // 错误地交换了参数,但编译器不会报错,因为存在隐式转换
return 0;
}
enum class 类型安全,不允许枚举常量的隐式转换,不同枚举类型之间也不能进行比较,必须通过显式转换才能将枚举常量转换为其他类型:
enum class A{
RED,
GREEN,
BLUE
};
enum class B{
APPLE,
BANANA
};
// 枚举常量不能隐式转换为int
int value= A::RED; // 错误
int value = static_cast<int>(A::low); // 正确
// 枚举常量与其他数值比较
if (A::GREEN== 1) { // 错误
// ...
}
// 不同枚举类型之间不能比较
if (A::GREEN== B::BANANA) { // 编译错误
// ...
}
void process(A a, B b) {
// ...
}
int main() {
A a = A::BLUE;
B b = B::BANANA;
process(b, a); // 编译错误
return 0;
}
2.3 前置声明支持
enum 不支持前置声明:
enum Status; // 编译错误,必须同时定义
// 必须像这样声明并定义
enum Status {
success,
failure
};
enum class 支持前置声明:
// enum class支持前置声明
enum class Status; // 正确,前置声明
// 在其他地方进行定义
enum class Status {
success,
failure
};
同时 enum class支持底层类型指定:
// C++11中,显式指定底层类型的enum支持前置声明
enum Status : int; // 正确,前置声明并指定底层类型为int
// 定义enum
enum Status : int {
success,
failure
};
3.高级用法
3.1 安全的转换函数
enum class Status : int {
Success = 0,
Failed = -1,
Timeout = -2
};
// 封装转换函数
constexpr int to_int(Status s) {
// 强转底层类型,C++11 起支持 constexpr
return static_cast<std::underlying_type_t<Status>>(s);
}
int main() {
Status s = Status::Success;
// 显式转换(正确)
int val = to_int(s); // val = 0
return 0;
}
3.2枚举值遍历
#include <array>
#include <iostream>
enum class Color : uint8_t {
Red,
Green,
Blue,
Yellow
};
// 定义枚举值列表(C++11 起可用 std::array)
constexpr std::array<Color, 4> ColorValues = {
Color::Red, Color::Green, Color::Blue, Color::Yellow
};
// 遍历函数
void print_all_colors() {
for (auto c : ColorValues) {
int val = static_cast<uint8_t>(c);
std::cout << "Color: " << val << std::endl;
}
}
// C++17 增强:constexpr 遍历
template <typename Enum, auto& Values>
constexpr void for_each_enum(auto&& callback) {
for (const auto& e : Values) {
callback(e);
}
}
int main() {
print_all_colors();
// C++17 遍历(编译期安全)
for_each_enum<Color, ColorValues>([](Color c) {
std::cout << "Enum value: " << static_cast<int>(c) << std::endl;
});
return 0;
}
3.3作为容器键
enum class HttpStatus : uint16_t {
OK = 200,
CREATED = 201,
BAD_REQUEST = 400,
NOT_FOUND = 404,
INTERNAL_ERROR = 500
};
// 作为map键
std::map<HttpStatus, std::string> status_messages = {
{HttpStatus::OK, "OK"},
{HttpStatus::CREATED, "Created"},
{HttpStatus::NOT_FOUND, "Not Found"},
{HttpStatus::INTERNAL_ERROR, "Internal Server Error"}
};
// 有序遍历
for (const auto& [status, message] : status_messages) {
std::cout << static_cast<int>(status) << ": " << message << std::endl;
}
3.4运算符重载
// 为枚举类定义运算符
enum class FilePermission : uint8_t {
NONE = 0b000,
READ = 0b001,
WRITE = 0b010,
EXEC = 0b100,
ALL = READ | WRITE | EXEC
};
// 位运算运算符
inline FilePermission operator|(FilePermission lhs, FilePermission rhs) {
return static_cast<FilePermission>(
static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
}
inline FilePermission operator&(FilePermission lhs, FilePermission rhs) {
return static_cast<FilePermission>(
static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
}
inline FilePermission operator^(FilePermission lhs, FilePermission rhs) {
return static_cast<FilePermission>(
static_cast<uint8_t>(lhs) ^ static_cast<uint8_t>(rhs));
}
inline FilePermission operator~(FilePermission p) {
return static_cast<FilePermission>(~static_cast<uint8_t>(p));
}
inline FilePermission& operator|=(FilePermission& lhs, FilePermission rhs) {
lhs = lhs | rhs;
return lhs;
}
// 使用方法
FilePermission perms = FilePermission::READ | FilePermission::WRITE;
if ((perms & FilePermission::READ) != FilePermission::NONE) {
// 有读权限
}

更多推荐


所有评论(0)