声明枚举变量:Weekday today = WED;——和声明 int n = 3; 一个样。用法的核心是三条"能与不能":① 能用枚举值赋值(today = FRI;);② 不能直接拿整数赋值(today = 3; 编译错,要强转);③ 不能用 cin >> 输入(但可以用 cout << 输出数字)。枚举变量内部存的就是整数。
8.6.1 定义了类型,这一节使用变量。这里的规则和 8.1.2(结构体变量)是一组对照:结构体变量能整体赋值、能用 . 访问成员;枚举变量能赋枚举值、能比较。新东西是那三条"限制"——它们是 C++ 给枚举加的"安全带",理解它们才知道枚举为什么比 const int 更好用。
一、声明与赋值
enum Weekday { MON, TUE, WED, THU, FRI, SAT, SUN };
Weekday today; // 先声明(此刻是垃圾值,和普通变量一样)
today = WED; // 用枚举值赋值 ✅
Weekday rest = SUN; // 声明时初始化 ✅
Weekday a = MON, b = TUE; // 一行声明多个 ✅
注意:Weekday today; 不初始化时也是垃圾值(2.3.2 的老规矩)——别拿它去比较。
二、核心:三条"能与不能"
✅ 能用枚举值赋值
today = FRI;
if (today == SAT) { ... }
❌ 不能直接用整数赋值
today = 3; // ❌ 编译错(C++ 里)
为什么? 因为 C++ 给枚举加了类型保护:Weekday 和 int 是两种类型,不能自动互转。这恰恰是枚举的价值所在——
int day = 3; // 3 到底是星期三还是别的?编译器不管
Weekday day2 = 3; // ❌ 编译器立刻拦住你
真想强塞一个整数,必须明确地转换(就是在跟编译器说"我知道我在干什么"):
today = (Weekday)3; // 强制转换 —— 能编过,但你自己负责
today = static_cast<Weekday>(3); // C++ 风格的写法(更规范)
实用建议:看到
(Weekday)3这种写法要警惕——它往往意味着"这个数字应该有个名字了"。正路是加进枚举列表。
❌ 不能直接输入
cin >> today; // ❌ 编译错
要输入就用一个临时 int 中转:
int tmp;
cin >> tmp;
today = (Weekday)tmp; // 明确转换
这也提醒你:枚举不适合"让用户直接输入"。用户输入的是数字,还得转成枚举。更常见的做法是让用户选菜单(1/2/3),程序内部再映射成枚举值。
✅ 能输出(但输出的是数字)
cout << today << endl; // 输出 2(不是 "WED"!)
原因:编译后枚举值就是整数,"WED" 这个名字在程序里根本不存在(8.6 讲过)。
想输出名字,就得自己准备一张"名字表":
const char *weekNames[7] = {"周一","周二","周三","周四","周五","周六","周日"};
cout << weekNames[today] << endl; // 用枚举值当下标 → 周三
三、能隐式转成整数(单向)
枚举 → 整数是允许的(隐式):
Weekday today = WED;
int n = today; // ✅ n = 2
cout << today + 1 << endl; // ✅ 3(参与算术会先转成 int)
整数 → 枚举是不允许的(必须强转):
Weekday d = 2; // ❌
Weekday d2 = (Weekday)2; // ✅ 但要自己负责
用一张表记住这个"单向":
| 方向 | 能自动吗 | 例子 |
|---|---|---|
枚举 → int |
能 | int n = today; |
int → 枚举 |
不能(要强转) | today = (Weekday)2; |
四、枚举变量占多大
cout << sizeof(Weekday) << endl; // 通常是 4(等于 int)
和你写几个枚举值无关——enum Color { RED, GREEN, BLUE }; 也是 4 字节。因为底层用整数存。
某些编译器会按取值范围压缩(比如值都在 0~255 就用 1 字节)——所以这个数字以你机器实测为准,通常见到的是 4。
五、动手 Demo:枚举变量的能与不能
#include <iostream>
using namespace std;
enum Weekday { MON, TUE, WED, THU, FRI, SAT, SUN };
int main() {
// ✅ 用枚举值赋值
Weekday today = WED;
cout << "today = " << today << "(输出的是数字)" << endl;
// ✅ 用枚举值比较
if (today == WED) cout << "今天是周三" << endl;
// ✅ 枚举隐式转 int
int n = today;
cout << "转成 int 后 n = " << n << endl;
// ✅ 当作数组下标 → 得到名字
const char *names[7] = {"周一","周二","周三","周四","周五","周六","周日"};
cout << "名字:" << names[today] << endl;
// ✅ 强制转换(不推荐,但合法)
today = (Weekday)5;
cout << "强转成 5 后:" << names[today] << endl;
// ❌ 下面两行如果取消注释,编译会报错
// today = 3; // 不能直接用整数赋值
// cin >> today; // 不能直接输入
cout << "sizeof(Weekday) = " << sizeof(Weekday) << " 字节" << endl;
return 0;
}
看到什么算成功:
today = 2(输出的是数字)
今天是周三
转成 int 后 n = 2
名字:周三
强转成 5 后:周六
sizeof(Weekday) = 4 字节
三个看点:
- cout << today 输出 2,不是 WED——枚举值就是整数,名字只活在源码里;
- int n = today; 合法(枚举 → int 的方向是通的);
- names[today] 直接当下标——这是"输出枚举名字"的标准做法。
30 秒实验:把注释掉的 today = 3; 取消注释再编译。记下报错信息(多半是 invalid conversion from 'int' to 'Weekday' 这类)——这条报错就是 C++ 给你的"安全带"。然后再改成 today = (Weekday)3;,编译就过了。一个强制转换符号,就是从"编译器把关"变成"你自己负责"。
六、常见误区
- "
cout << today会打印 WED"——打印的是数字。枚举名在编译后就没了。想要名字,自己准备名字数组。 - "枚举变量可以随便赋整数"——C++ 里不行(要强转)。这条限制正是枚举的价值:它能在编译期拦住"写了一个不存在的状态"这种错误。
- "枚举变量可以用
cin输入"——不行。要让用户输入,得先读进int再强转(或者干脆用菜单编号)。 - "枚举不能参与运算"——能。枚举值隐式转成
int后可以做加减比较(下一节 8.6.3)。 - "
sizeof(枚举)等于枚举值的个数"——错。它存的是一个整数,大小通常 4 字节,和值的个数无关。
自测三问(点开对答案)
1. `today = 3;`(`today` 是 `Weekday` 类型)能编译过吗?怎么办?——不能。要么改成枚举值,要么明确强转 `today = (Weekday)3;`。 2. `cout << today;` 会输出什么?想要输出"周三"怎么办?——输出**数字 2**。想要名字就自己建一个名字数组,用枚举值当下标。 3. 枚举和 `int` 之间,哪个方向能自动转换?——**枚举 → `int` 能**(隐式);`int` → 枚举**不能**(必须强转)。- ☐ 8.6.3 枚举类型的运算(下一节)
相关笔记
- 枚举类型的声明 —— 上一节:编号规则
- 枚举类型的运算 —— 下一节:比较与遍历(含实例06)
- 表达式中的类型转换 —— 强转语法
- 变量的声明及赋值 —— 未初始化就是垃圾值
- 🔷 C++基础 · 索引 —— 全课路线图