继承与组合的权衡
比较继承和组合,并根据设计选择合适的工具
继承与组合的权衡 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。
复用代码的两种方式
您可以通过从另一个类继承来复用代码,也可以将其作为成员进行组合。两种方式都有适用场景。
继承:“是一种”
当派生类确实是基类的一种特殊类型时,请使用继承。
class Vehicle {};
class Car : public Vehicle {}; // a Car IS a Vehicle
class SportsCar : public Car {};组合:“拥有某物”
当关系是“拥有某物”或“使用某物”时,请使用组合。
class Engine {};
class Car {
Engine engine_; // a Car HAS an Engine
};耦合权衡
继承会产生紧密耦合——派生类依赖于基类的内部实现。组合可以保持模块彼此独立,也更容易修改。
灵活性
组合允许在运行时改变行为——您可以替换被组合的对象。继承则会在编译期绑定行为。
class Logger {
std::unique_ptr<LogSink> sink_; // can swap implementations
public:
void setSink(std::unique_ptr<LogSink> s) { sink_ = std::move(s); }
};测试
组合对象可以替换为模拟对象来进行测试。如果没有虚函数或模板,继承的基类会更难模拟。
脆弱基类问题
基类中的修改可能会破坏许多派生类。组合可以将变化隔离在进行组合的类中。
选择继承的情况
在以下情况下适合使用继承:
- 存在清晰的“是一种”关系
- 需要通过基类接口实现多态
- 基类明确是为继承而设计的
选择组合的情况
在以下情况下适合使用组合:
- 希望灵活替换实现
- 关系是“拥有某物”或“使用某物”
- 希望降低耦合并简化测试
策略模式
将组合与多态结合起来:存储一个指向策略对象的基类指针,并由宿主类对该对象进行组合。
class Sorter {
std::unique_ptr<SortStrategy> strategy_;
public:
void sort(std::vector<int>& v) { strategy_->execute(v); }
};混入与策略类
对于编译期定制,请使用模板化策略类——这属于类型层面的组合。它功能强大,且没有运行时开销。
接口 + 组合
一种常见的现代模式是:定义一个接口(抽象基类),并组合实现该接口的具体类。接口使用继承,实现使用组合。
快速检查
哪种方式通常能提供更大的灵活性和更松散的耦合?
总结
继承表示“是一种”,组合表示“拥有某物”。组合更加灵活、耦合更低,因此代码复用时应优先选择组合。对于通过接口实现的多态,可以使用继承,并通常将其与组合实现结合起来。
常见问题解答
「继承与组合的权衡」课时是免费的吗?
是的 — 「继承与组合的权衡」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。
「继承与组合的权衡」这节课中我会学到什么?
比较继承和组合,并根据设计选择合适的工具 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C++ Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「继承与组合的权衡」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C++ Academy 课中编写并运行代码吗?
能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 单继承与多继承
- 虚函数与 vtable
- 抽象类与纯虚方法
- 继承与组合的权衡