第2章封面

第 2 章回答一个哲学问题:写数据结构之前,先想清楚「它对外承诺什么」。这个承诺就是 ADT(抽象数据类型)

🎫 ADT:先定合同,再盖楼

ADT 只规定「能做什么」(接口),不规定「怎么做到」(实现)。书里最爱用的例子是股票交易记录buysell、查询最赚钱的交易——用户只关心合同条款,不管内部是数组还是链表。

封装(encapsulation) 就是把「怎么做」藏进私有区域:

class StockDB {
private:
    // 内部实现:随便换,用户无感
public:
    void buy(...);          // 合同条款
    int bestProfit() const; // 合同条款
};

用户代码只依赖 public 部分——将来你把数组换成哈希表,用户代码一行不改,这就是接口的力量 ✨。

🧬 继承与多态:家族企业

  • 继承(inheritance):子类自动获得父类的成员,「is-a」关系。Circle : public Shape——圆是一种形状;
  • 多态(polymorphism):同一个 draw() 调用,Circle 对象画圆、Square 对象画方块——运行时自动分派

C++ 的实现机制是虚函数

class Shape {
public:
    virtual void draw() const = 0;  // 纯虚 = 只定合同
    virtual ~Shape() {}             // 虚析构!多态基类必加 ⚠️
};
class Circle : public Shape {
public:
    void draw() const override { /* 画圆 */ }
};

⚠️ 新手必踩的坑:通过基类指针 delete 派生类对象时,如果析构函数不是 virtual,只析构一半——内存泄漏 + 未定义行为。书里专门拿红字标了这条。

🎨 模板:一招吃遍所有类型

排序 int 数组的代码,排序 double 时要复制粘贴一遍?模板(template)让类型变成参数:

template <typename T>
T findMax(const vector<T>& arr) {
    T best = arr[0];
    for (const T& x : arr)
        if (x > best) best = x;
    return best;
}

编译器会按需生成 findMax<int>findMax<string> 等版本——一套代码,处处编译。STL(C++ 标准模板库)就是这个思想的巅峰之作。

💥 异常:优雅地报警

数据结构经常遇到非法操作:弹空栈、越界访问。C++ 的答案是三件套:

throw std::out_of_range("stack is empty");  // 报警
try { s.pop(); }                            // 监听
catch (std::out_of_range& e) { /* 处理 */ } // 接住

设计原则:函数发现问题时「抛」,调用者决定怎么处理——责任划分清晰,程序不至于崩得莫名其妙。

🎯 本章通关清单

  • [ ] 能用自己的话说出 ADT 和实现的区别
  • [ ] 解释 virtual 析构函数为什么必须存在
  • [ ] 写出一个函数模板
  • [ ] 理解 throw/try/catch 的责任分工

下一章开始,真正的数据结构登场:数组、链表、递归!🧱