🔷 第八章 结构体与共用体
📄 一句话概括

声明枚举变量: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;,编译就过了。一个强制转换符号,就是从"编译器把关"变成"你自己负责"。

六、常见误区

  1. "cout << today 会打印 WED"——打印的是数字。枚举名在编译后就没了。想要名字,自己准备名字数组。
  2. "枚举变量可以随便赋整数"——C++ 里不行(要强转)。这条限制正是枚举的价值:它能在编译期拦住"写了一个不存在的状态"这种错误。
  3. "枚举变量可以用 cin 输入"——不行。要让用户输入,得先读进 int 再强转(或者干脆用菜单编号)。
  4. "枚举不能参与运算"——能。枚举值隐式转成 int 后可以做加减比较(下一节 8.6.3)。
  5. "sizeof(枚举) 等于枚举值的个数"——错。它存的是一个整数,大小通常 4 字节,和值的个数无关。
自测三问(点开对答案) 1. `today = 3;`(`today` 是 `Weekday` 类型)能编译过吗?怎么办?——不能。要么改成枚举值,要么明确强转 `today = (Weekday)3;`。 2. `cout << today;` 会输出什么?想要输出"周三"怎么办?——输出**数字 2**。想要名字就自己建一个名字数组,用枚举值当下标。 3. 枚举和 `int` 之间,哪个方向能自动转换?——**枚举 → `int` 能**(隐式);`int` → 枚举**不能**(必须强转)。

相关笔记