从 int 到 co_await,一张地图看完所有保留字
int class = 1;;override/final(不是关键字)和 const/constexpr/consteval(是关键字)这类最容易混的东西。-std=c++20 下真实编译运行核对过。输入任意一个词,看它是关键字(绝对不能用)、有含义的标识符(能用但别用)、 还是普通名字(随便用)。下面的一排词点一下就能试。
and、or、not 也是关键字C++ 标准给 11 个运算符准备了"英文别名",它们是关键字(不能当变量名),
但日常几乎没人用——因为键盘上 && 比 and 好打。选一个看它等价于什么。
int or = 1; 是编译错误,
很多人第一次遇到会以为是编译器抽风。点组名展开/收起。每组给一句话定位 + 代表代码 + 真实编译输出。 右侧标记告诉你这组在哪个阶段才深入学:阶段一 阶段二 阶段四。
override 和 final 是关键字?—— 不是。
它们是"有含义的标识符",只在虚函数声明末尾才有特殊作用,别处可以当普通变量名:
int override,
后面就没法再用 override 标注虚函数了——所以这是"能编译,但毁掉后续代码"的写法。import / module / await 是关键字?—— 目前不是。
本机 g++ 15.2 / -std=c++20 逐词实测:这三个词仍可用作变量名。
它们是 C++20 模块系统和协程的预留词,将来可能升级为关键字。transaction_safe 同理,从未进正式标准。const_cast 能改任何 const?—— 不能,改了就是 UB。
cx 常量折叠了,rx=99 改的内存和 cout 读的根本不是一回事。
能编译、能跑、不报错,但结果是错的——这类坑最阴。
const_cast 只能去掉"本来就不是 const 的对象"上的 const 限定。按分组筛选,或点"全部"。鼠标悬停看它属于哪一组。这张表可以当字典用。
int class、int new、int or 全部编译错误。
命名前用上面的检测器扫一眼,或干脆避开所有 92 个词。const=运行时不可改;constexpr=编译期可算(可递归);
consteval=强制只能编译期调用,传运行时变量直接编译错误;constinit=要求编译期初始化。and/or/not/bitand/xor/compl 等 11 个词都是保留字,
不能当标识符,哪怕你从来不用它们。override/final 是"有含义的标识符",只在虚函数声明末尾有特殊含义,可以当普通变量名(int override = 10; 实测合法)。而 nullptr(C++11)、constexpr(C++11)、thread_local(C++11) 都是真关键字。and、or、not 在 C++ 中等价于什么?&/|/~ 对应的替代写法是 bitand/bitor/compl;C 项的 &=/|=/!= 对应 and_eq/or_eq/not_eq。依据 ISO/IEC 14882:2020 §2.5 Alternative tokens。register 在 C++11 起语义被废弃、C++17 正式从标准移除(只保留为兼容占位符)。goto 从未被废弃(虽然不推荐用);volatile 在 C++20 中部分用法被废弃,但关键字本身仍是关键字。Q4. 阅读"常量与修饰符"组的代码,写出 factorial(5) 和 square(7) 的输出值。
并说明:constexpr 函数和 consteval 函数有什么本质区别?
factorial(5) = 120、square(7) = 49(本机实测)。constexpr 函数可以在编译期求值,但如果传的是运行时变量,它也能在运行时正常调用(两用);
consteval 函数只能在编译期调用,传运行时变量会直接编译错误("立即函数")。
另外 constexpr 允许递归,consteval 也允许,但都要求编译期能算完。
Q5. 阅读"类与面向对象"组的 union 代码:先 d.i = 42,再 d.f = 3.14f,
之后打印 d.i 为什么变成了 1078523331?
3.14f 覆盖了原来的 42。3.14f 的 IEEE 754 单精度位模式是 0x4048F5C3,转成十进制正好是 1078523331(本机实测一致)。Q6. 把下面 10 个关键字按本节的 12 组分类,并各写一句它的核心作用:
| 关键字 | 所属组 | 核心作用 |
|---|---|---|
mutable | 4 · 常量与修饰符 | 让成员即使在 const 成员函数里也能被修改(常用于缓存计数) |
co_yield | 12 · 协程 | 协程产出一个值并挂起,下次恢复时从这里继续 |
bitand | 替代写法 | 等价于 &(按位与) |
dynamic_cast | 11 · 类型转换 | 运行时安全向下转型,失败返回 nullptr 而不是崩 |
explicit | 7 · 类与 OOP | 禁止构造函数的隐式转换,防止 Student s = "abc" 这种意外 |
requires | 8 · 模板 | 给模板参数加约束,不满足时编译期就拦下(报错只有一行) |
thread_local | 5 · 存储类 | 每个线程各有一份独立副本,互不干扰 |
noexcept | 6 · 函数 | 承诺该函数不抛异常,编译器可据此优化 |
wchar_t | 1 · 基本类型 | 宽字符类型,Windows 上 2 字节(本机实测) |
default | 2 · 分支 | switch 的兜底分支;也用于 = default 生成默认函数 |
mutable 和 thread_local
都涉及"存储期与可变性",是最容易混的一对——前者管"const 方法里能不能改",后者管"每个线程各一份"。
int 它必须知道"这是要声明一个整数",而不是"这是个叫 int 的变量"。
唯一的办法就是事先约定一批词永远不能被用作名字——这就是保留字(关键字)。
if、while 是控制词,C++ 把它们锁死。语言要能被无歧义地解析,就必须有一部分词是"专用的"。
override 这种词不锁死,只在特定语法位置生效,
这样既能加新特性、又不会让十几年前的老代码突然编译失败——这叫向后兼容,
和工程里"加接口不改老接口"是同一个思想。阶段五的项目 A(自制一门小语言)你会亲手写这个"切词"的过程。