【经典书籍】C++ Primer 第14类虚函数与多态精华讲解
我们来一场既专业又好玩的 C++ 面向对象之旅,把第14章的核心内容——虚函数与多态(Virtual Functions and Polymorphism),用能听懂、记得住方式彻底讲透!
📘 《C++ Primer》第14章:虚函数与多态(Virtual Functions and Polymorphism)
🎯 一句话总结这一章是干嘛的?
第14章教你如何让 C++ 中的“对象”在运行时“智能地决定该干啥”,也就是让基类指针/引用能够调用到真正子类的函数,实现“一个接口,多种行为”的魔法,这就是传说中的多态(Polymorphism)!
你可以理解为:
就像你跟一群动物说:“来,表演个才艺!”🦁 狮子会吼,🐼 熊猫会吃竹子,🐧 企鹅会吐槽天气,而你只用了一个指令,它们却各自表演了不同的节目!
🧠 一、核心概念先搞懂(用最生活化的方式)
1️⃣ 什么是多态(Polymorphism)?
多态(Poly = 多,Morph = 形态)就是:同一个指令,不同的对象,做出不同的反应。
🎭 类比:公司开会点名发言
-
老板说:“每个人都说说自己最近在干啥~”
-
程序员说:“我在写代码,修 Bug。”
-
设计师说:“我在画图,改 UI。”
-
产品经理说:“我在写需求,改需求,再写需求。”
👉 老板用的是同一个问题,但每个人回答的内容和风格完全不一样!这就是多态!
在 C++ 里,多态通常是指:
用基类指针或引用调用虚函数时,实际执行的是派生类重写的那个版本!
2️⃣ 什么是虚函数(Virtual Function)?
虚函数就是告诉 C++ 编译器:“这个函数,我希望能在运行时动态决定调用谁的版本,而不是编译时固定死。”
语法很简单,在成员函数前加关键字:
virtual 返回类型 函数名(参数) { ... }
3️⃣ 什么是动态绑定(Dynamic Binding)?
当你通过基类指针或引用调用一个虚函数时,C++ 会在运行时根据实际对象的类型来决定调用哪个类的函数版本。
这就是多态的核心机制!
🧩 二、为什么要用虚函数和多态?(解决什么问题?)
❌ 问题场景:没有虚函数,基类指针只能调用基类函数
你有一个基类 Animal
,和几个派生类 Dog
、Cat
。
你用基类指针指向派生类对象,然后调用某个函数(比如 speak()
),如果函数不是虚函数,那么调用的永远是基类的版本!
Animal* a = new Dog();
a->speak(); // 如果 speak() 不是 virtual,调用的永远是 Animal::speak(),不是 Dog 的!
🤦 结果:你以为自己在听狗叫,实际上听到的是:“Animal sound...”(基类默认实现)
✅ 解决方案:使用虚函数!
把基类的函数声明为 virtual,然后派生类可以重写(override)它,这样当你通过基类指针或引用调用时,C++ 就会聪明地调用实际对象所属类的函数版本!
🧪 三、代码示例时间!(多态入门,超好懂)
🐕 场景:动物会“说话”(speak)
我们设计一个基类 Animal
和几个派生类:Dog
, Cat
, Cow
。
1️⃣ 基类:Animal(带虚函数)
#include <iostream>
using namespace std;class Animal {
public:// 虚函数:speakvirtual void speak() const {cout << "Animal says: Generic animal noise" << endl;}// 虚析构函数(后面解释为什么要有它!)virtual ~Animal() {}
};
✅ 注意:
virtual
关键字让这个函数支持多态调用!
2️⃣ 派生类:Dog, Cat, Cow(重写 speak)
class Dog : public Animal {
public:void speak() const override { // C++11 起推荐用 override 明确表示重写cout << "Dog says: Woof!" << endl;}
};class Cat : public Animal {
public:void speak() const override {cout << "Cat says: Meow!" << endl;}
};class Cow : public Animal {
public:void speak() const override {cout << "Cow says: Moo!" << endl;}
};
3️⃣ 主函数:多态调用!同一个指令,不同表现!
int main() {Animal* animals[] = { new Dog(), new Cat(), new Cow() };for (Animal* a : animals) {a->speak(); // 同一个函数调用,不同动物不同声音!delete a; // 记得释放内存}return 0;
}
🎤 输出结果:
Dog says: Woof!
Cat says: Meow!
Cow says: Moo!
✅ 这就是多态的魅力! 你只用了基类指针
Animal*
,却调用了各个派生类自己的 speak() 方法!
就像你喊了一声:“说话!”然后狗汪汪、猫喵喵、牛哞哞,自动适配!
🧠 四、虚函数与重写的细节(敲黑板!重点!)
1️⃣ 重写(Override)是什么?
派生类重新定义基类的虚函数,提供自己的实现。
C++11 开始,你可以用 override
关键字显式标记,让编译器帮你检查是否真的重写了基类虚函数,避免手滑写错函数名或参数。
void speak() const override; // 明确表示:我就是要重写基类的 speak()
2️⃣ 虚函数的特点:
特点 | 说明 |
---|---|
基类中用 virtual 声明 | 表示这个函数支持运行时多态 |
派生类中可重写(override) | 提供自己的实现 |
通过基类指针/引用调用时 | 实际调用的是对象所属类的版本 |
如果派生类没有重写 | 调用的还是基类的版本 |
3️⃣ 为什么基类要有虚析构函数?
当你用基类指针删除派生类对象时,如果基类析构函数不是虚函数,那么只会调用基类的析构函数,派生类部分不会被正确销毁 → 内存泄漏!
✅ 解决方案:基类析构函数要声明为 virtual!
virtual ~Animal() {}
🎯 记住:只要类里有可能被继承,并且可能通过基类指针删除派生类对象,基类析构函数就必须是虚的!
🧩 五、纯虚函数与抽象类(更高阶,但超有用!)
1️⃣ 什么是纯虚函数?
在基类中声明一个虚函数,但不提供实现,而是加
= 0
,这就叫纯虚函数。
语法:
virtual 返回类型 函数名(参数) = 0;
2️⃣ 什么是抽象类?
含有纯虚函数的类叫抽象类,它不能直接实例化(不能 new 一个抽象类对象!)
抽象类的目的是定义接口规范,强制派生类去实现这些纯虚函数。
🎯 例子:抽象类 Shape(图形)
class Shape {
public:// 纯虚函数:计算面积virtual double area() const = 0;// 纯虚函数:画图virtual void draw() const = 0;virtual ~Shape() {}
};
任何类想成为“图形”,就必须实现 area() 和 draw(),否则它自己也是抽象类,不能实例化!
派生类必须实现纯虚函数,否则也是抽象类:
class Circle : public Shape {
public:double area() const override { return 3.14 * radius * radius; }void draw() const override { cout << "Drawing a Circle" << endl; }private:double radius = 5.0;
};
🧠 六、虚函数使用场景总结(什么时候用?)
场景 | 是否用虚函数 / 多态 | 说明 |
---|---|---|
基类定义通用接口,派生类有不同实现 | ✅ 用虚函数 | 比如 Animal::speak(),Dog/Cat/Cow 各自发声 |
你希望通过基类指针调用派生类函数 | ✅ 用虚函数 + 动态绑定 | 运行时决定调用谁 |
你想定义“接口规范”,但不实现 | ✅ 用纯虚函数 + 抽象类 | 比如 Shape,强制子类实现 area() |
你只是想复用代码,不涉及运行时多态 | ❌ 不需要虚函数 | 比如普通工具类、数据模型 |
🎁 七、幽默总结(敲黑板,背下来!)
概念 | 幽默版解释 | 严肃版解释 |
---|---|---|
多态 | 同一个指令,不同的对象各自表演,就像开会点名,大家答案都不一样 | 同一个函数调用,根据对象类型执行不同版本的函数 |
虚函数 | 告诉编译器:“别绑死了,运行时再决定调用谁” | 基类函数支持动态绑定,允许派生类重写 |
动态绑定 | 运行时才决定调用谁,很灵活,像综艺节目的即兴发挥 | 通过基类指针/引用调用虚函数时,实际调用的是对象所属类的函数 |
纯虚函数 | “这个函数你必须自己实现,不然你别想实例化!” | 带 = 0 的虚函数,抽象类必备 |
抽象类 | 只定义规矩,不干活,逼着子类去实现 | 不能实例化,用于定义接口规范 |
✅ 本章学完你就能掌握什么?
技能 | 是否掌握 |
---|---|
理解什么是多态(一个接口,多种行为) | ✅ |
会使用 virtual 声明虚函数 | ✅ |
理解虚函数与重写(override)的关系 | ✅ |
知道动态绑定(运行时决定调用谁)的原理 | ✅ |
理解为什么要用虚析构函数 | ✅ |
会定义抽象类与纯虚函数 | ✅ |
能设计带有扩展性的类层次结构(比如图形、动物、插件等) | ✅ |
🚀 下一步学什么?(强烈推荐)
学完第14章,你已经掌握了 C++ 面向对象编程的灵魂机制之一:多态!
接下来可以继续深入学习:
-
第15章:模板与泛型编程(写出更通用的代码,比如模板类、模板函数)
-
第16章:面向对象与泛型设计模式(比如工厂模式、策略模式,大量基于继承与多态)
-
实战项目:
-
图形类系统(Shape → Circle / Square,多态绘图)
-
游戏角色系统(Character → Warrior / Mage,不同技能)
-
插件系统(基类接口,不同插件实现)
-
🎯 总结一句话(来,大声读出来!):
虚函数让 C++ 拥有了运行时的“智能判断力”,多态让程序拥有了“见人说人话,见鬼说鬼话”的超能力!
🔥 你现在已经正式踏入了 C++ 面向对象编程的“高阶玩家”领域
下面依次生成并详细讲解以下三个案例,每个都围绕虚函数、多态、抽象类、继承这些核心概念,并且:
-
✅ 代码完整可运行
-
✅ 注释详细、幽默风趣
-
✅ 附带图解思路与输出示例
-
✅ 适合练手、面试准备、项目原型
🎯 三个实战案例总览
案例 | 主题 | 说明 | 核心知识点 |
---|---|---|---|
1️⃣ 图形类系统(Shape 多态绘图) | 用多态绘制不同图形(圆、矩形) | 基类 Shape 定义纯虚函数,子类实现不同绘制与面积计算 | 抽象类、纯虚函数、多态、虚函数、override |
2️⃣ 游戏角色系统(Character 战士/法师) | 不同角色有不同技能与行为 | 基类 Character,派生类 Warrior / Mage,各自重写攻击与技能 | 继承、多态、虚函数、运行时行为差异化 |
3️⃣ 插件系统(抽象接口 + 多态加载) | 模拟插件架构,基类定义接口,不同插件实现功能 | 抽象类 Plugin,不同子类如 LoggerPlugin / AnalyticsPlugin | 接口设计、依赖倒置、多态、抽象与实现分离 |
🧩 案例 1️⃣:图形类系统(Shape 多态绘图系统)
🎨 场景描述
你正在开发一个绘图软件或图形引擎,需要支持多种图形:
-
圆形(Circle)
-
矩形(Rectangle)
-
(可扩展:三角形、多边形...)
每个图形都要能:
-
计算自己的面积
-
绘制自己(打印信息,模拟绘图)
我们用抽象类 + 多态来实现 —— 基类定义“接口”,子类负责“实现”。
🧱 代码实现
#include <iostream>
#include <memory>
#include <vector>
using namespace std;// 抽象类:Shape(图形)
class Shape {
public:// 纯虚函数:计算面积virtual double area() const = 0;// 纯虚函数:绘制图形virtual void draw() const = 0;// 虚析构函数virtual ~Shape() {}
};
派生类 1:Circle(圆形)
class Circle : public Shape {
private:double radius;public:Circle(double r) : radius(r) {}double area() const override {return 3.14159 * radius * radius;}void draw() const override {cout << "🔵 Drawing Circle with radius " << radius<< ", Area = " << area() << endl;}
};
派生类 2:Rectangle(矩形)
class Rectangle : public Shape {
private:double width, height;public:Rectangle(double w, double h) : width(w), height(h) {}double area() const override {return width * height;}void draw() const override {cout << "🟦 Drawing Rectangle " << width << "x" << height<< ", Area = " << area() << endl;}
};
🧪 主函数:多态调用绘图
int main() {cout << "===== 欢迎使用多态绘图系统 =====" << endl;vector<unique_ptr<Shape>> shapes;// 添加各种图形(多态对象)shapes.push_back(make_unique<Circle>(5.0));shapes.push_back(make_unique<Rectangle>(4.0, 6.0));// 统一调用:draw() 和 area(),实际调用了子类实现for (const auto& shape : shapes) {shape->draw();cout << "📐 Area: " << shape->area() << endl;cout << "-------------------------" << endl;}return 0;
}
🖼️ 输出结果(示例)
===== 欢迎使用多态绘图系统 =====
🔵 Drawing Circle with radius 5, Area = 78.5397
📐 Area: 78.5397
-------------------------
🟦 Drawing Rectangle 4x6, Area = 24
📐 Area: 24
-------------------------
✅ 你只用了 基类指针(Shape),却调用了不同的 draw() 和 area() 实现,这就是多态的力量!*
🧩 案例 2️⃣:游戏角色系统(Warrior / Mage 多态技能)
🎮 场景描述
你正在开发一款简单的 RPG 游戏,里面有不同类型的角色:
-
战士(Warrior):擅长近战,技能是“挥剑攻击”
-
法师(Mage):擅长魔法,技能是“释放火球”
所有角色都继承自一个基类 Character,并重写自己的攻击方式。
🧱 代码实现
基类:Character(角色)
#include <iostream>
#include <memory>
#include <vector>
using namespace std;class Character {
public:virtual void attack() const = 0; // 纯虚函数:攻击virtual ~Character() {}
};
派生类 1:Warrior(战士)
class Warrior : public Character {
public:void attack() const override {cout << "⚔️ Warrior attacks with a mighty sword slash!" << endl;}
};
派生类 2:Mage(法师)
class Mage : public Character {
public:void attack() const override {cout << "🔥 Mage casts Fireball!!! BOOM!" << endl;}
};
🧪 主函数:多态调用不同角色的攻击
int main() {cout << "===== RPG 角色技能展示 =====" << endl;vector<unique_ptr<Character>> party;party.push_back(make_unique<Warrior>());party.push_back(make_unique<Mage>());for (const auto& hero : party) {hero->attack(); // 同一个接口,不同的酷炫技能!cout << "-----------------" << endl;}return 0;
}
⚔️🔥 输出结果
===== RPG 角色技能展示 =====
⚔️ Warrior attacks with a mighty sword slash!
-----------------
🔥 Mage casts Fireball!!! BOOM!
-----------------
✅ 只用一个
Character*
接口,就能让战士和法师各自施展出专属技能,这就是多态 + 继承的典型应用!
🧩 案例 3️⃣:插件系统(抽象接口 + 多态加载)
🧩 场景描述
你正在设计一个支持插件的软件系统,比如日志系统、数据分析模块等等。
-
你定义了一个抽象插件接口(Plugin)
-
每个插件(如日志插件、统计插件)都继承这个接口,实现自己的功能
-
主程序动态加载插件(此处用模拟),并统一调用接口方法
🧱 代码实现
抽象类:Plugin(插件接口)
#include <iostream>
#include <memory>
#include <vector>
using namespace std;// 抽象插件接口
class Plugin {
public:virtual void execute() const = 0; // 插件执行逻辑virtual ~Plugin() {}
};
派生类 1:LoggerPlugin(日志插件)
class LoggerPlugin : public Plugin {
public:void execute() const override {cout << "📝 LoggerPlugin: Logging important events..." << endl;}
};
派生类 2:AnalyticsPlugin(分析插件)
class AnalyticsPlugin : public Plugin {
public:void execute() const override {cout << "📊 AnalyticsPlugin: Analyzing user behavior data..." << endl;}
};
🧪 主函数:模拟加载插件并执行
int main() {cout << "===== 模拟插件系统加载 =====" << endl;vector<unique_ptr<Plugin>> plugins;// 模拟加载插件plugins.push_back(make_unique<LoggerPlugin>());plugins.push_back(make_unique<AnalyticsPlugin>());// 统一调用插件功能for (const auto& plugin : plugins) {plugin->execute(); // 多态调用,实际运行时决定谁干活cout << "-------------------" << endl;}return 0;
}
🛠️ 输出结果
===== 模拟插件系统加载 =====
📝 LoggerPlugin: Logging important events...
-------------------
📊 AnalyticsPlugin: Analyzing user behavior data...
-------------------
✅ 你定义了一个统一的插件接口,不同的插件实现自己的逻辑,主程序无需关心具体是谁,只管调用
execute()
,这就是依赖倒置 + 多态的经典实践!
🎁 总结表格:三个案例核心要点
案例 | 核心类 | 多态函数 | 说明 | 适用场景 |
---|---|---|---|---|
1️⃣ 图形系统 | Shape(抽象) Circle / Rectangle | area() , draw() | 通过基类指针调用不同图形的面积与绘图 | 图形渲染、UI框架、绘图工具 |
2️⃣ 游戏角色 | Character(抽象) Warrior / Mage | attack() | 每个角色有不同技能,统一接口调用 | RPG游戏、技能系统、多角色行为 |
3️⃣ 插件系统 | Plugin(抽象) Logger / Analytics | execute() | 模拟插件架构,统一加载与调用 | 模块化设计、可扩展系统、中间件 |
✅ 你学到了什么?(终极 checklist)
技能 | 是否掌握 |
---|---|
什么是抽象类,什么是纯虚函数 | ✅ |
什么是多态,什么是动态绑定 | ✅ |
如何用基类指针/引用调用派生类函数 | ✅ |
为什么要用虚析构函数 | ✅ |
如何设计可扩展的类体系(图形/角色/插件) | ✅ |
能熟练使用 override 明确重写 | ✅ |
能用智能指针管理多态对象 | ✅ |
🚀 你接下来可以:
-
🧱 把这些案例扩展成带用户输入、菜单选择的控制台小游戏
-
🖼️ 把图形系统升级成带文件保存 / 绘图窗口的迷你项目
-
⚔️ 把 RPG 系统扩展成多个角色、装备、技能树
-
🧩 把插件系统变成真正动态加载 DLL / SO 的模块化架构(进阶)
🔥 已经真正掌握了 C++ 面向对象编程的“灵魂机制”——虚函数与多态,并且能灵活运用到实际项目中了!
把《C++ Primer》第14章「虚函数与多态(Virtual Functions and Polymorphism)」的内容画成思维导图或UML 图,这个想法非常棒!🎯
因为图表能让抽象的概念瞬间清晰,尤其是像继承、虚函数、多态、抽象类这种层层关联的核心机制。
🧠 一、思维导图(MindMap)—— 适合梳理逻辑与记忆
适合:快速理解、复习、记忆知识点之间的关系,适合打印 / 手绘 / 用XMind/MindNode等工具制作
📌 思维导图结构:《C++ 第14章 虚函数与多态》
🧩 C++ Primer 第14章:虚函数与多态
├── 1. 多态(Polymorphism)
│ ├── 定义:同一个接口,不同行为(运行时决定)
│ ├── 作用:提高代码扩展性、灵活性
│ └── 类比:同一命令,不同对象各自响应
│
├── 2. 虚函数(Virtual Function)
│ ├── 定义:基类中用 virtual 声明的成员函数
│ ├── 作用:允许派生类重写,实现运行时多态
│ ├── 语法:virtual 返回类型 函数名() { ... }
│ ├── 调用机制:通过基类指针/引用调用时动态绑定
│ └── 推荐使用 override(C++11)明确表示重写
│
├── 3. 动态绑定(Dynamic Binding)
│ ├── 发生时机:运行时(runtime)
│ ├── 条件:通过基类指针或引用调用虚函数
│ └── 效果:调用实际对象(派生类)的函数版本
│
├── 4. 纯虚函数(Pure Virtual Function)
│ ├── 定义:virtual 返回类型 函数名() = 0;
│ ├── 作用:定义接口,但不提供实现
│ └── 包含纯虚函数的类 → 抽象类
│
├── 5. 抽象类(Abstract Class)
│ ├── 定义:包含至少一个纯虚函数的类
│ ├── 特点:不能直接实例化(不能 new)
│ ├── 作用:定义规范,强制派生类实现纯虚函数
│ └── 派生类必须实现所有纯虚函数,否则也是抽象类
│
├── 6. 虚析构函数(Virtual Destructor)
│ ├── 定义:基类析构函数声明为 virtual
│ ├── 作用:防止通过基类指针删除派生类对象时内存泄漏
│ └── 规则:只要类可能被继承,且可能用基类指针删除,析构函数就要是 virtual
│
└── 7. 应用场景(实际使用案例)├── 🖼️ 图形类系统(Shape → Circle/Rectangle)├── ⚔️ 游戏角色系统(Character → Warrior/Mage)└── 🧩 插件系统(Plugin → Logger/Analytics)
✅ 你可以用这个结构轻松画成中心放射状思维导图,中心是“虚函数与多态”,然后每个主要概念作为一级分支,再展开细节。
🧩 二、UML 类图(UML Class Diagram)—— 适合理解类关系与设计
适合:展示类之间的继承关系、虚函数、抽象类等设计结构,适合画在纸上 / UML工具(如 StarUML、PlantUML、Lucidchart)中
📌 UML 类图结构(文字版,可画成标准类图)
我们以三个典型类层次为例,组合在一套 UML 图中表达:
1️⃣ 抽象类:Shape(图形基类,含纯虚函数)
+----------------+
| <<abstract>>|
| Shape |
+----------------+
| # virtual |
| double area() const = 0; |
| # virtual |
| void draw() const = 0; |
| # virtual ~Shape() {} |
+----------------+^|
-----------------------------
| |
▼ ▼
+---------+ +-------------+
| Circle | | Rectangle |
+---------+ +-------------+
| -radius | | -width |
| | | -height |
| +area() | | +area() |
| +draw() | | +draw() |
+---------+ +-------------+
✅ Shape 是抽象类(通常可画成斜体类名或加 «abstract»),包含两个 纯虚函数 area() 和 draw()
Circle 和 Rectangle 是具体类,继承 Shape 并实现(override)这两个函数
2️⃣ 抽象类:Character(角色基类)
+----------------+
| <<abstract>>|
| Character |
+----------------+
| # virtual |
| void attack() const = 0; |
| # virtual ~Character() {} |
+----------------+^|
-----------------------------
| |
▼ ▼
+---------+ +-------------+
| Warrior | | Mage |
+---------+ +-------------+
| +attack()| | +attack() |
+---------+ +-------------+
✅ Character 是抽象类,定义了一个纯虚函数 attack(),Warrior 和 Mage 继承它并实现各自的攻击方式
3️⃣ 抽象类:Plugin(插件接口)
+----------------+
| <<abstract>>|
| Plugin |
+----------------+
| # virtual |
| void execute() const = 0; |
| # virtual ~Plugin() {} |
+----------------+^|
-----------------------------
| |
▼ ▼
+-------------+ +------------------+
| LoggerPlugin| | AnalyticsPlugin |
+-------------+ +------------------+
| +execute() | | +execute() |
+-------------+ +------------------+
✅ Plugin 是一个插件接口(抽象类),定义 execute(),具体插件如日志、统计模块去实现它
🧩 UML 类图中你将看到的关键符号与含义:
符号 / 标记 | 含义 |
---|---|
<<abstract>> 或 类名斜体 | 表示抽象类(含纯虚函数,不能直接实例化) |
virtual 函数 | 可被重写,支持多态(尤其是纯虚函数 = 0) |
空心三角箭头 ↑ | 表示继承关系(is-a),子类指向父类 |
= 0 | 表示纯虚函数,该类为抽象类 |
virtual ~ClassName() | 虚析构函数,防止派生类对象被错误析构 |
🛠️ 三、如何画出来?(工具推荐)
🎨 思维导图工具推荐:
-
XMind(强大易用,适合思维导图)
-
MindNode(Mac 上超好用)
-
FreeMind(免费开源)
-
手绘也超赞!用中心主题 + 分支梳理上面的结构
🧩 UML 工具推荐:
-
PlantUML(文本描述生成 UML,超方便!)
-
StarUML(可视化拖拽,适合画类图)
-
Lucidchart(在线协作,支持 UML)
-
Draw.io(免费!支持类图、继承等,简单拖拽)
📥 四、还可以生成:
✅ 选项 1:PlantUML 代码(直接粘贴就能生成 UML 图!)
比如,下面是 Shape 抽象类 + Circle / Rectangle 继承关系的 PlantUML 代码:
@startuml
skinparam classAttributeIconSize 0abstract class Shape {<<abstract>>{abstract} double area() const{abstract} void draw() constvirtual ~Shape()
}class Circle {- double radius+ double area() const+ void draw() const
}class Rectangle {- double width- double height+ double area() const+ void draw() const
}Shape <|-- Circle
Shape <|-- Rectangle
@enduml
👉 你可以把这段代码粘贴到 PlantUML 在线编辑器 中,立刻生成标准 UML 类图!
✅ 选项 2:手绘版示意图(文字描述你可以照着画)
比如这张简笔画你可以画在笔记本上:
[ Shape (抽象) ]/ | \[Circle] [Rect] [Triangle](area) (area) (area)(draw) (draw) (draw)
✅ 总结
你想要的 | 我为你准备了什么 |
---|---|
思维导图 | 完整的《第14章 虚函数与多态》知识点结构,分层清晰,便于记忆与复习 |
UML 类图 | 抽象类、继承、纯虚函数、多态的类关系图,可画在工具中或手绘 |
工具推荐 | XMind / PlantUML / StarUML / Draw.io,总有一款适合你 |
代码生成 | PlantUML 可直接运行的类图代码,一键生成专业图表 |
图像化学习 | 把抽象概念变成直观结构,理解更深刻,面试 / 复习超好用 |
🎁 下一步建议
-
🧠 先画思维导图梳理知识脉络,搞懂虚函数、多态、抽象类之间的关系
-
🖍️ 再画 UML 类图理解类层次、继承与接口设计
-
💻 最后结合前面三个实战案例(图形 / 角色 / 插件)加深理解与运用
🔥 现在已经不仅仅是理解了虚函数与多态,而是可以从设计、实现、画图、应用多个维度真正掌握它!