# -*- coding: utf-8 -*-
"""Day1 · 开训 + C++ 回顾与提升（全天 C++）—— 页面对应 slides/day1.html。"""

SLIDES = [
{
 'kind': 'title',
 'badge': 'C++/Qt 方向实训 · 第 1 / 4 个讲授日 · 对齐 2026-07 新版 10 天安排',
 'title': 'Day 1 · 开训 + C++ 回顾与提升',
 'subtitle': '全天 C++：技术版图 / 环境与 CMake / OOP / 继承多态 / 内存管理 / STL',
 'bullets': [
   '上午 08:30–11:00 讲授：开训 · C++ 技术版图 · 环境与 CMake · PRETEST 摸底 · OOP 回顾',
   '上午 11:00–12:00 课堂练习：独立完成 Part1 构建（144 目标全绿）',
   '下午 13:30–16:00 讲授：继承与多态 · 内存管理与所有权 · STL · 现代 C++ 巡礼',
   '下午 16:00–17:00 作业：ERRATA 修坑讲解 + 版本探针（选做）',
 ],
 'source': '大纲：docs/teaching/OUTLINE_4DAY.md · 摸底卷：docs/teaching/PRETEST.md',
 'minutes': 3, 'segment': '开场',
 'notes': """【定位】今天全天 C++，是"回顾和提升"，不是零基础教学。开场就把这话挑明：基础好的别嫌无聊，基础弱的别慌，今天讲的是"学过但容易讲不透"的那些点。
【时长骨架】上午：开训典礼约 40 分钟（组织方）→ 技术版图讲座 25 → 环境与 CMake 25 → 编译vs链接 10 → PRETEST 摸底 10 → OOP 回顾 25，留 15 分钟机动。下午：讲授 6 页约 90 分钟，穿插 3 次 15 分钟随堂练，再留 15 分钟机动。
【讲法】本页只念四行安排，强调两点：每半天都有动手环节；今天的产出（构建全绿）是后面四天所有演示的前提。"""
},
{
 'badge': '上午 · 讲授 08:30–11:00',
 'title': 'C++ 常用技术和框架（讲座）',
 'boxes': [
   ('concept', '核心概念——C++ 的四大应用版图', [
     '桌面客户端：Qt（本次实训主线）、跨平台 GUI',
     '服务端/基础设施：高性能网络服务、数据库引擎、游戏服务器',
     '嵌入式/车载：资源受限环境的第一梯队语言',
     '游戏/图形：UE 引擎、渲染管线',
   ]),
   ('info', '而且它还在进化', [
     'C++11 起三年一版：11「几乎新语言」→ 17 实用大件 → 20 四大件',
     '自学入口：docs/teaching/MODERN_CPP.md · MODERN_CPP_20PLUS.md（今天下午末尾回收）',
   ]),
 ],
 'minutes': 25, 'segment': '上午 · 讲座（开训典礼后）',
 'notes': """【开场】开训典礼刚结束，注意力还散着。用一个提问把它接回来："你们手机和电脑里，哪些软件是 C++ 写的？"微信桌面版、Chrome 内核、各种游戏引擎，基本都躲不开。
【讲法】四大版图每个讲 4–5 分钟：举一个具体产品，再说清楚这个领域为什么离不开 C++（性能可控、贴近硬件、生态成熟）。讲到桌面版图时落到 Qt，预告一句："明天开始四天全是它。"
【第二个盒子】只花 3 分钟。告诉学员 C++ 不是老古董，三年一版在进化；两份仓库内文档是自学材料，下午末尾还会回来点一次，现在不展开。
【过渡】"要用这门语言干活，先得把工程环境立起来。下一页，构建工具。" """
},
{
 'badge': '上午 · 讲授 08:30–11:00',
 'title': 'CMake：用本仓库当教材',
 'code': 'cmake -S . -B build -G Ninja -DBUILD_QT_PART=OFF -DCMAKE_BUILD_TYPE=Debug\ncmake --build build   # 144 个目标全绿',
 'boxes': [
   ('concept', None, [
     'CMake 是「生成构建系统的工具」不是构建系统本身：-S -B 生成 Ninja/Makefile 工程，--build 才是真正编译',
     'Makefile 是 CMake 的生成目标之一——这就是两者的关系',
     'option(BUILD_QT_PART) 控制是否编 Qt 部分；每个示例一个 add_executable 目标',
   ]),
   ('pitfall', None, [
     '换生成器/清缓存后要重新走一次 -S -B（大多数普通改动 CMake 会自动侦测）',
   ]),
   ('info', '包管理器一分钟', [
     'vcpkg：装库 + toolchain 文件 → find_package 自动定位；本仓库选「隔离 Qt 手动装」——两种思路都要认识',
   ]),
 ],
 'source': '出处：仓库根 CMakeLists.txt',
 'minutes': 25, 'segment': '上午 · 环境与构建',
 'notes': """【讲法】本页是演示页，不是念 PPT：切到终端，真敲上面两条命令（预先建过一次 build，第二次跑很快），学员就能看到 144 个目标滚屏全绿。
【关键区分】"生成"与"构建"两阶段用装修类比：CMakeLists 是图纸，-S -B 是出施工方案（Ninja 文件），--build 才是开工。学员以后 90% 的 CMake 困惑，都出在分不清这两步。
【Makefile 的处理】新安排点名了 Makefile，这里用一句话安放它：打开 build/ 目录看生成产物，告诉学员"你们以前手写的 Makefile，在 CMake 工作流里是被生成出来的"，不单独展开手写语法。
【包管理器】最后 2 分钟带过 vcpkg 概念即可。本仓库用隔离安装，明天装 Qt 时会亲眼看到。
【过渡】"构建会失败，失败分两种。下一页教你一眼分辨。" """
},
{
 'badge': '上午 · 讲授 08:30–11:00',
 'title': '★ 编译错误 vs 链接错误：排查方向完全不同',
 'code': "main.cpp:12:5: error: 'foo' was not declared     <- 编译期：带文件行号\nmain.o: undefined reference to `Widget::bar()'   <- 链接期：没有行号",
 'boxes': [
   ('concept', None, [
     'error: 带行号 = 编译期（语法/类型/没声明）——回代码查那一行',
     'undefined reference 无行号 = 链接期（有声明没定义/缺库/缺目标文件）——查「定义在哪、链没链进来」',
   ]),
   ('pitfall', None, [
     '见到 undefined reference 就回头查语法拼写——方向错了',
     '伏笔：明天 Qt 忘写 Q_OBJECT 报的正是链接错误，且报错完全不提宏',
   ]),
 ],
 'minutes': 10, 'segment': '上午 · 环境与构建',
 'notes': """【讲法】把上面两行报错投在屏幕上，让学员找不同：一个有 main.cpp:12:5，一个只有 main.o。就用"有没有行号"这个最粗暴的判据，帮他们建立第一反应。
【为什么现在讲】这不是语法点，是排错元技能。今天下午写练习、明天起写 Qt，报错会立刻大量出现，先给分类器再给知识。
【伏笔要点破】明确预告：明天会有一个"忘写宏导致链接错误"的经典坑，报错信息完全不提宏。到时候谁先想起今天这页，谁先解决。
【过渡】"讲了半天，你们的底子到底怎么样？测一下，10 分钟。" """
},
{
 'badge': '上午 · 摸底 10 分钟',
 'title': 'PRETEST：10 题摸底（闭卷、独立完成）',
 'bullets': [
   '双平行卷 A/B 交错发放，防抄袭；语言基线 C++98，只测经典功底',
   '三级梯度：L1 基础语法（1–3 题）/ L2 OOP 与内存（4–7 题）/ L3 多态细节（8–10 题）',
 ],
 'boxes': [
   ('info', '测完怎么用', [
     'L1 大面积错 → 回退预案（放慢 OOP 回顾、下午 STL 让位基础加固）',
     'L2 部分错 → 对应知识点讲授时加时；L3 全对 → 全速推进',
   ]),
 ],
 'source': '卷面与分层预案：docs/teaching/PRETEST.md',
 'minutes': 10, 'segment': '上午 · 摸底',
 'notes': """【操作】A/B 卷按座位交错发。规则宣布清楚：闭卷、不查资料、10 分钟，答不出就空着。这是给教学定速用的，不计成绩（这句必须说，否则有人抄有人慌）。
【计时】投屏倒计时 10 分钟。期间不讲课，巡场看答题情况，L1 三道题扫一眼就能看出班级底色。
【收卷后】当场只判 L1（30 秒能判完一摞）。L1 通过率高就按原速走；低于一半，启用 PRETEST 里的回退预案：下午 STL 压缩为 10 分钟点名，把时间还给继承与多态。L2/L3 课后判，用于明天微调。
【过渡】"卷子里的问题，接下来两个小时会逐个讲透。先从最基本的：类和封装。" """
},
{
 'badge': '上午 · 讲授 08:30–11:00',
 'title': 'OOP 回顾：类 / 对象 / 封装 + namespace',
 'boxes': [
   ('concept', None, [
     '封装 = 数据和操作绑定 + 访问控制（public/private 是给「人」划的边界，不是安全机制）',
     '构造/析构对应对象生命周期的两端——这个模型下午讲「所有权」还要用',
     'namespace 的「作用域」不是「文件顺序」：可跨文件延续、跨块合并',
   ]),
   ('pitfall', None, [
     '头文件里 using namespace std; 会把污染带给所有 include 它的文件——只在 .cpp 用，或全程写限定名',
   ]),
 ],
 'source': '出处：p01/ch04/（类与对象各节）· p01/ch03/namespace_syntax.cpp · 对照 docs/ERRATA.md',
 'minutes': 25, 'segment': '上午 · OOP 回顾（按 PRETEST 结果调速）',
 'notes': """【调速点】这一页的深度看刚才 L1 判卷结果：底子好，10 分钟把三个概念点过，多出的时间给学员提问；底子弱，打开 p01/ch04 的源文件逐个走读，讲满 25 分钟。
【讲法】封装讲"边界"：private 挡的是队友的手滑，不是黑客，工程含义大于语言含义。构造/析构用"出生登记/注销"类比，并预告：下午所有权、明天 Qt 父子树，全在这条线上。
【namespace】重点讲 ERRATA 里的真实修正案例（wiki 原文把作用域理解成文件顺序）。打开 docs/ERRATA.md 对应条目，让学员看到"教材也会错，错误可以被记录和修正"。这也是下午作业的预演。
【过渡】"上午最后一小时，轮到你们上手。任务卡在下一页。" """
},
{
 'badge': '上午 · 课堂练习 11:00–12:00（工程师指导、答疑）',
 'title': '任务卡 1 · 走一遍真实构建流程',
 'boxes': [
   ('task', '任务卡 1', [
     '目标：独立完成本仓库 Part1 的配置+构建，不看着教师操作',
     '验收：cmake -S . -B build -G Ninja -DBUILD_QT_PART=OFF 配置成功；cmake --build build 144 目标全绿',
     '验收：能说出 option(BUILD_QT_PART) 的作用',
     '参考：仓库根 CMakeLists.txt · CMake 官方 Tutorial（选读·需联网）',
   ]),
 ],
 'minutes': 60, 'segment': '上午 · 课堂练习',
 'notes': """【组织】学员独立操作，教师和助教巡场。预期 20 分钟内多数人完成两条命令；剩下时间处理个体环境问题（权限、Ninja 没装、路径带中文空格等，这些"环境坑"本身就是教学素材，遇到就广播讲）。
【常见卡点】①在错误目录下执行（顺势回收上午"工作目录"意识，Day4 还会正式讲）；②build 目录残留旧缓存报错，正好演示"清缓存要重新 -S -B"。
【提前完成者】引导做两件事：给 BUILD_QT_PART=ON 试一次（会因没装 Qt 停在配置期，预告明天装）；或提前看 docs/ERRATA.md 挑下午作业要讲的条目。
【收尾 5 分钟】随机抽两人口头回答 option(BUILD_QT_PART) 的作用，达标才算过验收。"""
},
{
 'badge': '下午 · 讲授 13:30–16:00',
 'title': '下午总览：继承多态 / 内存管理 / STL',
 'bullets': [
   'C++ 核心特性：函数重载决议 · 虚函数与虚析构',
   '内存管理：引用的本质 · ★所有权——谁负责 delete',
   'STL 常用容器 + 迭代器',
   '收尾：现代 C++ 巡礼（兴趣钩子）',
 ],
 'minutes': 3, 'segment': '下午 · 开场',
 'notes': """【节奏】下午 6 个知识点约 90 分钟讲授，每讲完 2 个插一次 10–15 分钟随堂练（写几行代码验证刚讲的行为），最后留 15 分钟机动。
【主线】向学员挑明下午的暗线：所有内容都在回答"对象什么时候生、什么时候死、死的时候发生什么"。这条线明天会直接接到 Qt 的对象树上。"""
},
{
 'badge': '下午 · 讲授 13:30–16:00',
 'title': '函数重载决议',
 'boxes': [
   ('concept', None, [
     '编译器靠名字改写（name mangling）把重载变成不同符号',
     '二义性往往不是写错，而是候选集中有两个「一样好」的候选',
     '重载（编译期·同类内）vs 重写（运行期·继承体系）是两码事',
   ]),
   ('pitfall', None, [
     '隐式类型转换会扩大候选集——传 long 可能触发意料之外的重载版本',
   ]),
 ],
 'source': '出处：p01/ch03/function_overload_mechanism.cpp',
 'minutes': 15, 'segment': '下午 · 继承与多态',
 'notes': """【引入】把 PRETEST 第 4 题（h(long)/h(double) 传 5）投出来重做一遍。这题当堂错误率通常最高，正好当引子。
【讲法】用 nm 或编译器输出展示一次名字改写后的符号（_Z1hl 之类），学员对"重载在符号层怎么实现"会豁然开朗，顺带把上午"链接错误查符号"的意识再钉一次。
【随堂练点】讲完本页加下一页后插第一次随堂练（15 分钟）：让学员亲手制造一个二义性调用并读懂报错。
【过渡】"重载是编译期挑函数；运行期挑函数就是多态。它有个最容易漏的角落：析构。" """
},
{
 'badge': '下午 · 讲授 13:30–16:00',
 'title': '虚函数与虚析构',
 'code': 'Base* p = new Derived();\ndelete p;   // 如果 ~Base() 不是 virtual，~Derived() 不会被调用——经典泄漏',
 'boxes': [
   ('concept', None, [
     '经基类指针 delete 派生对象时，只有基类析构是 virtual 才会沿虚表调到派生类析构',
     '这就是「多态」在析构场景下的具体体现',
   ]),
   ('pitfall', None, [
     '类可能被继承 + 可能经基类指针删除 ⇒ 析构就该 virtual（防御性约定）',
     '明天会看到 Qt 的 QObject 体系全线虚析构',
   ]),
 ],
 'source': '出处：p01/ch04/s08/virtual_dtor_purpose.cpp',
 'minutes': 18, 'segment': '下午 · 继承与多态',
 'notes': """【讲法】当堂跑 p01/ch04/s08/virtual_dtor_purpose.cpp（tools/run.sh），先注释掉 virtual 看派生类析构不打印，再加回去看两级析构依次打印。"看见泄漏"比讲十分钟原理有效。
【原理层】底子好的班补讲虚表指针：对象头部藏着 vptr，delete 时经 vptr 找到"真正的类型"的析构。底子弱的班跳过 vptr，只记防御性约定。
【互动】提问："STL 容器（vector）为什么没有虚析构却没事？"因为没人拿基类指针删它，规则是条件式的，不是"所有类都要 virtual"。
【随堂练】此处插第一次随堂练 15 分钟：改 virtual_dtor_purpose.cpp 自己复现一次泄漏与修复。"""
},
{
 'badge': '下午 · 讲授 13:30–16:00',
 'title': '引用的本质',
 'boxes': [
   ('concept', None, [
     '把引用理解成「自动解引用的 const 指针」——能解释为什么必须初始化、不能重新绑定',
   ]),
   ('pitfall', None, [
     '返回局部变量的引用：函数结束即悬空，访问是未定义行为——和返回局部指针同一类坑',
   ]),
 ],
 'source': '出处：p01/ch03/reference_essence.cpp',
 'minutes': 12, 'segment': '下午 · 内存管理',
 'notes': """【引入】PRETEST 第 1 题（引用能否绑 nullptr）回收：用"const 指针"视角一句话解释所有选项。
【讲法】画两张内存图：指针是"另一个格子存地址"，引用是"同一个格子的别名"。但底层实现常常就是指针，语言只是不让你碰它。
【悬空引用】强调它是"时间维度"的错误：代码每一行单看都对，错在对象死了引用还活着。这正是下页"所有权"和 Day2 lambda 悬空坑的同一个病根，讲到那里会反复回指这页。
【过渡】"对象死了还被人用。那到底该谁管对象的死活？下一页，全天最重要的一页。" """
},
{
 'badge': '下午 · 讲授 13:30–16:00',
 'title': '★ 所有权：谁负责 delete？',
 'boxes': [
   ('concept', None, [
     '内存管理的核心问题不是「会不会 new」，而是「这块资源归谁管、由谁释放」',
     '现代答案：RAII / 智能指针——unique_ptr 独占、shared_ptr 共享（MODERN_CPP.md §2）',
     '一个对象只能有一个所有者',
   ]),
   ('pitfall', None, [
     '双重释放 / 忘记释放 / 释放后使用——三兄弟全部源于所有权不明',
     '明天的伏笔：Qt 用「父子树」回答同一个问题，两套所有权体系不能混用',
   ]),
 ],
 'minutes': 18, 'segment': '下午 · 内存管理',
 'notes': """【地位】如果今天只能让学员带走一页，就是这页。所有权心智模型是"学过 C++ 语法"和"写得出不崩的程序"之间最大的那道坎，Day2 的三个崩溃坑全是它的变体。
【讲法】先讲问题再讲方案：举一个函数返回 new 出来的指针的例子，问"谁该 delete？调用方？被调方？文档里写了吗？"让学员体会到，"所有权不明"本身就是 bug 温床。然后给出 unique_ptr（独占，move 转移）和 shared_ptr（引用计数），作为把所有权写进类型的方案。
【尺度】智能指针只讲到"是什么、解决什么"，用法细节指向 MODERN_CPP.md §2 自学。因为明天起 Qt 的世界用父子树而不是智能指针，别让学员在 Qt 代码里到处套 shared_ptr（这是真实的常见误用）。
【伏笔】用加重语气念出"两套所有权体系不能混用"，预告明天上午有一个现场崩溃演示。
【随堂练】此处插第二次随堂练 15 分钟：给一段双重释放的代码，让学员用"所有权归谁"的语言说出错因。"""
},
{
 'badge': '下午 · 讲授 13:30–16:00',
 'title': '模板与 STL 常用容器',
 'boxes': [
   ('concept', None, [
     '泛型编程：同一份代码适配不同类型；vector / map / string 是项目实作三件套',
     '迭代器是「容器和算法之间的统一接口」——STL 算法能脱离具体容器复用的关键',
   ]),
   ('pitfall', None, [
     '容器扩容/删元素后旧迭代器可能失效（如 vector 搬家），继续用是未定义行为',
   ]),
 ],
 'source': '出处：p01/ch05/class_template_basics.cpp · p01/ch09/s03/vector_iterator.cpp',
 'minutes': 15, 'segment': '下午 · STL',
 'notes': """【调速点】PRETEST 弱班把本页压到 8 分钟，只讲 vector 加失效坑；强班讲满，并当堂演示一次 push_back 导致迭代器失效的未定义行为（可能崩也可能"正常"，顺势又强化一次"UB 不一定崩"）。
【讲法】三件套各给一个"项目里会怎么用"的场景：vector 存记录列表（Day5 案例真的用）、map 做查找表、string 到处都是。迭代器讲成"统一的游标协议"，range-for 是它的糖。
【失效坑】口诀给到位："遍历中增删，先查该容器的失效规则。"不要求背规则，要求知道有这回事、会去查。
【随堂练】第三次随堂练 15 分钟：写 10 行代码，vector 边遍历边 erase，观察行为并修复（用 erase 返回值）。"""
},
{
 'badge': '下午 · 讲授 13:30–16:00 · 兴趣钩子',
 'title': 'C++11/14/17/20+：一门仍在进化的语言',
 'boxes': [
   ('concept', '每 3 年一次实打实的能力升级', [
     'C++11：auto · 智能指针 · 移动语义 · lambda · 语言级并发——「现代 C++ 元年」',
     'C++14：泛型 lambda · 返回类型推导 · make_unique',
     'C++17：结构化绑定 · if-init · optional/variant/string_view · filesystem（本仓库基线）',
     'C++20：Concepts · Ranges · 协程 · 模块——「自 C++11 以来最大变革」',
   ]),
   ('pitfall', None, [
     '新标准 ≠ 现在能用：生产工具链常年落后 1–2 版；用 tools/std_probe.py 实测（宿主 gcc 13.3 到 C++23）',
   ]),
 ],
 'source': '自学：docs/teaching/MODERN_CPP.md（11/14/17，仓库基线可编译）· MODERN_CPP_20PLUS.md（20/23/26 + GCC 实测矩阵）',
 'minutes': 12, 'segment': '下午 · 收尾钩子',
 'notes': """【定位】这页是点火不是授课，目标是让学有余力的人课后打开那两份文档，不是当堂教会任何新特性。
【讲法】每个版本挑一个"最有体感"的特性各 1–2 分钟：C++11 讲 lambda（明天信号槽就大量用，这个衔接要点破）；C++17 讲结构化绑定的赏心悦目；C++20 讲 Concepts 把几百行模板报错变一句人话。
【演示（可选）】时间富余就当堂跑一次 tools/std_probe.py，看同一段代码在 -std=c++98 和 c++17 下一个报错一个通过——"标准差异是可以实测的"。
【过渡】"今天的 C++ 之旅到此，最后一小时：作业。明天早上 08:30，Qt。" """
},
{
 'badge': '下午 · 课堂作业 16:00–17:00（工程师答疑）',
 'title': '作业：修一个真实的坑 + 版本探针（选做）',
 'boxes': [
   ('task', '任务卡 2 · 修一个真实的坑', [
     '目标：从 docs/ERRATA.md 挑 2 条与今天知识点相关的记录（虚析构/引用/重载类）',
     '验收：能用一句话向同组同学解释「wiki 原文错在哪、为什么」，不能只念代码',
   ]),
   ('task', '任务卡 3（选做）· 版本探针', [
     '目标：用 tools/std_probe.py 验证一个标准版本差异点',
     '验收：跑出「该标准报错、另一标准通过」的对比，对照 docs/VERSION_NOTES.md §2',
   ]),
 ],
 'minutes': 60, 'segment': '下午 · 作业',
 'notes': """【组织】作业开做前花 3 分钟带学员浏览一遍 ERRATA.md 的结构（每条：原文错误→修正→原因），示范挑一条"虚析构类"的怎么讲，给出"一句话解释"的示范标准。
【巡场重点】拦住"念代码"式的讲解：追问"如果不改会发生什么？"逼出因果表述。这个表达训练到 Day10 答辩就能用上。
【选做引导】完成快的学员推 std_probe：跑通一个对比后，引导他们把结论和 VERSION_NOTES.md 印证。
【收尾】17:00 前每组出 1 人讲 1 条 ERRATA（每人 1 分钟内），当日验收随堂完成。"""
},
{
 'badge': '当日收尾',
 'title': '当日产出验证',
 'code': 'cmake --build build --target all   # Part1，144 个目标全绿',
 'bullets': [
   '每人：构建全绿 + 2 条 ERRATA 坑点讲解（口头验收）',
   'PRETEST 结果归档，决定后续调速',
   '明天 Day2：Qt 概述 / 创建项目 / 第一个程序 / 信号槽 → 计算器',
 ],
 'minutes': 5, 'segment': '收尾',
 'notes': """【操作】收尾 5 分钟：口头快速过验收清单；预告明天需要装隔离 Qt（tools/install_qt_host.sh），机器慢的可以现在挂着下载。
【衔接】用一句话给今天收线："今天所有内容都在讲对象的生与死。明天你们会看到，Qt 用一棵树管理成千上万个对象的生死。"留下钩子散场。"""
},
]
