第13章 程序的“血缘关系”(类继承)

探索类与类之间的“血缘”——继承。学习如何重用代码,并掌握面向对象编程中最强大的特性:多态。

环节 1:代码重用与继承

继承允许一个新类(派生类)获得一个已存在类(基类)的所有特性,并添加自己的新功能。这是一种强大的代码重用机制,模拟了现实世界中的“is-a”(是一种)关系。

// 基类 "父辈" class Pet { private: std::string name; public: Pet(const std::string& n) : name(n) {} void show() const; }; // 派生类 "子代" class Dog : public Pet { // "is-a" Pet private: std::string breed; public: // 派生类构造函数,通过初始化列表调用基类构造函数 Dog(const std::string& n, const std::string& b) : Pet(n), breed(b) {} // 把 n 传给 "父辈" };

派生类构造模拟器 🏗️

`Dog` 对象在构造时,必须先调用 `Pet` 的构造函数来完成“父辈”部分的初始化。观察这个过程。

Dog 对象

Pet 基类部分

name: ...

breed: ...

> 等待构造...

环节 2:多态 —— 一种指令,多种行为

多态是OOP的魔力所在。通过**虚函数 (virtual function)**,我们可以使用一个基类指针来调用不同派生类对象的同名方法,程序会在**运行时**智能地选择正确的版本。这就是**动态联编**。

多态行为观察室 🔬

我们有一个基类指针 `Pet* ptr`。让它分别指向不同的动物对象,然后调用 `ptr->show()`,观察会发生什么。

🐈

Pet

🐕

Dog

🐅

Tiger

当前: Pet* ptr = &pet_obj;

> Console Output:

class Pet { public: // virtual 关键字开启了动态联编 virtual void show() const; }; class Dog : public Pet { public: void show() const override; // 重写基类方法 }; class Tiger : public Pet { public: void show() const override; // 重写基类方法 }; // main 函数中 Pet* ptr; Dog my_dog; ptr = &my_dog; ptr->show(); // 运行时发现ptr指向Dog, 调用Dog::show()

终点站:编程挑战

练习 1:宠物与狗

任务:

定义一个 `Pet` 基类和一个 `Dog` 派生类。`Dog` 类继承 `Pet`,并添加自己的 `breed`(品种)成员。为 `Dog` 定义构造函数,使用初始化列表正确地初始化基类部分。

预期知识点:

公有派生,基类构造调用,成员初始化列表。

点击查看参考答案
#include <iostream> #include <string> using namespace std; class Pet { private: string name; public: Pet(const string& n) : name(n) {} void show() const { cout << "Name: " << name; } }; class Dog : public Pet { private: string breed; public: Dog(const string& n, const string& b) : Pet(n), breed(b) {} void show() const { Pet::show(); cout << ", Breed: " << breed << endl; } };
练习 2:多态报表

任务:

修改 `Pet` 基类中的 `show()` 方法,使其成为虚函数。使用 `Pet` 指针指向 `Dog` 对象,再次调用 `show()` 方法,验证动态联编是否生效。

预期知识点:

虚函数 `virtual`,动态联编,`override` 关键字。

点击查看参考答案
// Pet 类需要修改 class Pet { public: // 1. 将 show 声明为虚函数 virtual void show() const { /* ... */ } // 2. 基类析构函数也应为虚函数 virtual ~Pet() {} }; // Dog 类可以添加 override 关键字 (好习惯) class Dog : public Pet { public: void show() const override { /* ... */ } }; int main() { Dog my_dog("Rocky", "Bulldog"); Pet* pet_ptr = &my_dog; // 因为 show() 是虚函数, 这里会调用 Dog::show() pet_ptr->show(); // 输出 Rocky 和 Bulldog return 0; }