C++启蒙课程:第13章  类继承

我们将揭开OOP最强大的特性:类继承!这就像让你的新机器人自动拥有父辈的全部技能,并能“形态变化”!

🧬

基因的传递:公有继承

学习 "is-a" 关系,以及“父子蓝图”如何通过构造函数传递特性。

🦸

形态变化:虚函数与多态

掌握 `virtual` 关键字,让“形态变化”的英雄能执行不同的 `Work()`。

📜

架构设计:抽象基类

学习 `virtual ... = 0`“强制契约”,设计不能被实例化的通用接口。

课时一:基因的传递:公有继承与构造

(覆盖知识点 13.1.1 - 13.1.4)

“父子蓝图” (is-a 关系)

公有继承 (: public Base) 就像“基因传递”。子类 (Car) 自动获得父类 (Vehicle) 的所有公有特性。

Vehicle 蓝图 (父)
- wheels (private)
+ show_wheels() (public)
Car 蓝图 (子)
// 基类 (父) class Vehicle { int wheels; public: void show_wheels() const; }; // 派生类 (子) "is-a" 关系 class Car : public Vehicle { int passengers; // 新增特性 public: void show_details() const; };

“基类优先入场” (构造)

构造子类时,必须先调用父类的构造函数(使用 : 语法),把“基因”部分先组装好。

// 派生类构造函数 Car::Car(int w, int p) : Vehicle(w), // 1. 必须先调用基类构造 passengers(p) // 2. 再初始化自己的成员 { // 3. 函数体 }

课时二:形态变化:虚函数与多态

(覆盖知识点 13.2.1 - 13.2.5)

“动态调度机器人” (虚函数)

`virtual` 关键字告诉C++进行“动态联编”。机器人 🤖 会在“运行时”检查指针的“实际形态”,并调用正确版本的函数。

💡 互动:

Employee* ptr = ?

📜 代码支撑:

class Employee { public: // 1. 在基类中声明为 virtual virtual void Work() const { ... } }; class Manager : public Employee { public: // 2. 派生类重写 (override) void Work() const override { ... } }; class Technician : public Employee { public: // 2. 派生类重写 void Work() const override { ... } }; // 3. 通过基类指针调用 // ptr->Work(); // (机器人会动态检查 ptr 的真实类型)

课时三:抽象蓝图与继承适用性

(覆盖知识点 13.3 - 13.4)

13.3 “强制契约” (纯虚函数)

纯虚函数 (= 0) 是一个“强制契约”。任何包含它的类(ABC)都不能被实例化。派生类**必须**实现这个函数才能被创建。

Piano : public Instrument
// 抽象基类 (ABC) class Instrument { public: // 13.3 纯虚函数 " = 0 " // (强制契约) virtual void Play() const = 0; }; // Instrument i; // 错误! class Piano : public Instrument { public: // 派生类必须实现 Play() void Play() const override { ... } }; // Piano p; // OK!

继承的“判断法则”

公有继承只适用于 **"is-a" (是一种)** 关系。如果只是“包含”关系 (has-a),应使用组合(成员对象)。

"is-a" (是一种) ➡️ 继承
🚗 (Car) is-a ⚙️ (Vehicle)
"has-a" (有一个) ➡️ 组合
🚗 (Car) has-a 🔩 (Engine)
// "is-a" 关系 class Car : public Vehicle { // ... }; // "has-a" 关系 class Engine { ... }; class Car { private: Engine motor; // 组合 };

编程实践与作业

是时候检验你作为“OOP架构师”的实力了!

练习 1:Vehicle 与 Car (is-a 继承)

任务:

编写一个 Vehicle 基类(含 `wheels`),派生出 Car 类(新增 `passengers`)。实现 Car 的构造函数,确保它能正确调用基类构造函数。

点击查看参考答案
#include <iostream> using namespace std; class Vehicle { // 基类 private: int wheels; public: Vehicle(int w) : wheels(w) {} void show_wheels() const { cout << "轮子数量: " << wheels; } }; // 13.1 公有继承 class Car : public Vehicle { private: int passengers; // 新增属性 public: // 13.1 派生类构造函数调用基类构造函数 Car(int w, int p) : Vehicle(w), passengers(p) {} void show_details() const { show_wheels(); // 访问基类方法 cout << ", 载客数: " << passengers << endl; } };
练习 2:虚函数与多态 (Employee)

任务:

编写 Employee 基类 (含 virtual void Work()),派生出 ManagerTechnician。在 main 中使用基类指针数组 Employee* staff[2] 指向不同对象,演示多态。

点击查看参考答案
#include <iostream> using namespace std; class Employee { public: // 13.2 声明为虚函数 virtual void Work() const { cout << "进行基础工作。" << endl; } virtual ~Employee() {} // 虚析构函数 }; class Manager : public Employee { public: void Work() const override { // 重写 cout << "经理:正在制定战略。" << endl; } }; class Technician : public Employee { public: void Work() const override { // 重写 cout << "技术员:正在解决问题。" << endl; } }; int main() { Employee* staff[2]; // 基类指针数组 staff[0] = new Manager(); staff[1] = new Technician(); // 向上转换 // 13.2 多态调用 staff[0]->Work(); // 调用 Manager::Work staff[1]->Work(); // 调用 Technician::Work delete staff[0]; delete staff[1]; return 0; }
练习 3:抽象基类 (Instrument)

任务:

编写一个抽象基类 Instrument (含纯虚函数 Play())。派生 PianoGuitar 类并实现 Play()。演示 ABC 无法实例化,但指针可以实现多态。

点击查看参考答案
#include <iostream> using namespace std; // 13.3 抽象基类 (ABC) class Instrument { public: // 13.3 纯虚函数 virtual void Play() const = 0; virtual ~Instrument() {} }; class Piano : public Instrument { public: void Play() const override { cout << "钢琴:正在弹奏。" << endl; } }; class Guitar : public Instrument { public: void Play() const override { cout << "吉他:正在弹奏!" << endl; } }; int main() { // Instrument i; // 错误!不能实例化ABC Instrument* orchestra[2]; orchestra[0] = new Piano(); orchestra[1] = new Guitar(); orchestra[0]->Play(); orchestra[1]->Play(); delete orchestra[0]; delete orchestra[1]; return 0; }

本章知识点总结与复习

核心概念 解释/功能 关键用法/示例
公有继承模拟 is-a 关系,派生类是基类的特例。class Derived : public Base {}
派生构造函数必须调用基类构造函数来初始化基类部分。Derived(...) : Base(...) { ... }
多态性相同的调用,导致依赖于对象类型的行为。ptr->Work();
虚函数使用 `virtual` 关键字,启用多态(动态联编)。virtual void func() const;
向上转换允许将派生类指针/引用赋给基类指针/引用。Base * p = &derived_obj;
抽象基类 (ABC)包含纯虚函数的类,不能被实例化。class Instrument { ... };
纯虚函数虚函数声明后跟 `= 0`,强制派生类实现。virtual double Area() const = 0;
is-a vs. has-a继承 (is-a) vs. 组合 (has-a)。class Car { Engine m; };