pusidun
← All posts

侯捷 C++ 下册导读:从类的接口走向泛型与对象模型

侯捷 C++ 六门课程总目录

会写一个类以后,新的问题通常不是“再记住几个关键字”。为什么自定义类型能参加 4 + f 这样的表达式?为什么迭代器能够像指针一样使用,算法却不用知道容器布局?为什么一行基类接口调用最终执行了派生实现?为什么 new 失败时,还需要讨论另一种 delete

这些问题分别牵涉接口、泛型与对象模型,但都在追问同一件事:源码里的简短表达式,究竟向编译器和调用者承诺了什么。本组笔记沿着这条线阅读侯捷课程的下册。

来源档案:讲者为侯捷;片头原课名为《C++程序設計 (II) 兼談對象模型》(C++ Programming (part II), and Object Model),画面带 Boolan 博览与云课堂标识。本次使用 B 站账号 DetachmentSy 上传的《侯捷 - C++面向对象高级开发(下)》,BV1kBh5zrEWL,当前共 24 个上传分 P。上传者与原讲者分别署名;当前版本于 2025 年上传,原始录制年份及原课程完整性未核实。本文对应 P1《导读》,核对日期为 2026-09-12。

这是 AI 辅助初加工的学习笔记。音轨转录保留时间轴,再用课件校正术语与代码;文中的现代补充和原创实验单独说明,不作为课堂原话。回看时间只对应上述上传版本。链接保留分 P 与秒数参数;本次浏览器可核对分 P 页面,但播放器未能在该环境播放,故仍在表中写明时间与关键词,自动跳转未实测。

本门阅读路线

文章按问题归并分 P。先用类型转换理解表达式如何选出操作,再看类怎样提供访问与调用接口,之后沿模板、对象模型和分配机制继续深入。

文章 主要问题 对应分 P
一、下册导读(本文) 怎样区分泛型、面向对象与实现模型 P1
二、类型转换与代理 Fraction 的两个转换方向怎样影响加法 P2–3
三、指针式类与函数对象 类怎样向算法提供访问和调用接口 P4–5
四、模板与成员转换 类型参数、实参推导与跨类型初始化如何配合 P6–9
六、auto、范围 for 与引用 类型推导、值与别名怎样影响修改和重载 P14 后半、P15

先修知识:能解释自己写的那个类

导读明确说,下册是前一门面向对象程序设计课程的续篇,但可以独立选读,不要求学生一定看过上册。这里的“独立”是课程关系,不能理解为完全零基础。

读到类型转换之前,最好已经能解释构造函数、成员函数、const 对象和运算符重载;读到模板之前,应当熟悉一种具体类型的函数与容器;读到对象模型之前,需要知道公有继承、指针、引用与虚函数在源码层面的用途。如果这些还不能用一个小例子讲清楚,先补基础,再返回本课,会比直接背虚表图更有效。

一个实用的自测是:给一个持有资源的类增加复制操作,能够说明谁拥有资源、什么时候释放,以及两个对象是否共享同一份状态。这个问题联系到本站对象唯一性、共享与历史快照中讨论的生命周期契约。设计模式描述协作结构,这门课则帮助检查这些结构落在 C++ 上是否仍然成立。

为什么原课名没有把“面向对象”放在中心

P1 开头专门解释了命名。下册也谈模板与泛型,侯捷认为只用“面向对象”概括并不贴切。因此来源卡同时保留原课名和上传名:读者在 B 站看到的是“面向对象高级开发(下)”,课件上的课程范围则更宽。

课程将泛型编程与面向对象编程作为两条技术主线。二者可以共享类、封装与接口设计的经验,却不依赖同一种替换机制。使用虚函数时,调用可以通过基类接口到达具体对象的实现;使用模板时,算法所需的操作由类型参数在实例化时提供。看见 class 并不能据此断言这段程序采用了运行时多态。

这是读后续课件的一条判断线索:一个接口允许替换的究竟是对象、类型,还是某个行为?替换在什么阶段发生?如果能回答这两个问题,智能指针、函数对象、成员模板和虚函数就不会只是互不相干的语法词条。

本站流程、算法、状态与通知讨论了模板方法与策略。后续阅读对象模型时,可以重新问:模板方法里的普通成员函数为何能调用到派生类覆写的步骤?这里的“模板方法”是设计模式名称,和 C++ 的 template 不是同一个概念。

底层模型要解释行为,而不是代替规则

导读列出的 thisvptrvtbl 和虚机制,目标是帮助理解虚函数造成的多态行为。顺序值得保留:先知道调用应当做什么,再学习常见编译器怎样实现它。

整理者补充:课件中的布局图适合建立直觉;标准层面的保证、ABI 的布局约定、某个旧编译器的观察结果,是三个不同层次。仅凭一张“对象里放一根虚指针”的图,不能推导所有类型的大小、所有平台的字段偏移,也不能据此用强制转换读取对象内部结构。

学习时可以同时保留两种笔记:一栏记录语言保证的可观察行为,另一栏记录课堂所用实现如何完成它。后面的实验会优先验证调用和生命周期结果,对布局数据注明环境。这比把某次 sizeof 的数字记成规则更容易迁移。

书目是分层学习线索

导读的书目不是一串要求全部读完的清单。它实际上区分了四种需要:全面理解语言、借鉴专家经验、使用标准库、深入库实现。

课堂书目线索 它适合帮助回答的问题
《C++ Primer》第五版、《The C++ Programming Language》第四版 某个语言机制的完整语义是什么
Scott Meyers 的《Effective C++》与《Effective Modern C++》 何时该用或不该用某种机制
《The C++ Standard Library》第二版 标准库提供哪些组件、如何使用
《STL 源码剖析》 算法、容器与迭代器怎样协作实现

上述版本是视频里的历史书目,不代表当前版本推荐。课堂也立即修正了“库内部很少继承”的宽泛说法:旧实现较直接,新实现可能将一个类拆成多个基类和辅助类,阅读难度因而增加。这个自我限定很值得回看——不能拿旧实现的结构概括所有标准库版本。

整理者补充:容器和算法大量采用泛型技术,不表示整个标准库没有其他机制。例如标准库的流和异常类型同样值得分别研究。阅读一个实现时,先找出用户可见的契约,再辨认实现为复用、平台适配或性能增加的层次,不必把每一个内部基类都理解成业务上的“是一种”。

重点回看

讲次与时间 识别线索 值得回看的原因
P1 · 00:18–01:25 原课名、泛型与对象模型 解释上传标题与课程自身命名为什么不同
P1 · 01:40–02:24 “你應具備的基礎” 区分课程可独立选读与知识零先修
P1 · 03:40–05:01 Generic Programming、this、vptr、vtbl 把两条编程主线与底层模型联系起来
P1 · 08:49–10:15 STL 源码、旧版与新版继承关系 观察讲者如何给实现经验加上版本条件

带着可检验的问题继续

  1. 找一个自己写过的类,列出“可以调用哪些操作”和“内部保存什么”两张清单。然后替换内部存储,编译原来的调用代码。哪些错误说明实现细节已经泄露到接口?
  2. 读到一项课堂结论时,先标注它属于语言规则、库契约还是实现观察。检验方法是问:换一套符合标准的编译器或标准库,它是否必须仍成立?不能回答时,保留疑问,等后面的最小实验与规范链接验证。
  3. 选同一个“可替换步骤”,分别画出通过虚函数提供实现、通过模板参数提供实现的调用关系。此处不要求立即比较速度,先确定替换时机及调用者知道的类型信息。