克隆模式实现疑问:派生类Clone函数如何调用基类Clone实现?
解决Clone模式中基类与派生类的成员克隆复用问题
你的问题在多态Clone模式里很典型——怎么让基类和派生类各自负责自己的成员克隆,避免重复写冗余代码。先说说你当前实现的问题:Derived::clone()只创建了Derived实例并复制了mX,但完全没处理基类的mScripts向量;如果手动在每个派生类里写克隆mScripts的代码,又会大量重复,违反DRY(Don't Repeat Yourself)原则。
下面给你两种简洁的解决方案,核心思路都是拆分克隆逻辑,让基类负责基类成员,派生类只处理自己的新增成员:
方案一:提取基类成员克隆的辅助函数
把基类中克隆mScripts的逻辑抽成一个受保护的辅助函数,让派生类可以直接调用,不用重复写向量克隆的代码:
#include <memory> #include <vector> // 假设ScriptBase是你的多态脚本类,有自己的clone函数 class ScriptBase { public: virtual std::unique_ptr<ScriptBase> clone() const = 0; virtual ~ScriptBase() = default; }; class Base { public: virtual std::unique_ptr<Base> clone() const { auto cloned = std::make_unique<Base>(); copyBaseMembersTo(cloned.get()); return cloned; } protected: // 辅助函数:将当前对象的基类成员复制到目标对象 void copyBaseMembersTo(Base* dest) const { for (const auto& script : mScripts) { dest->mScripts.push_back(script->clone()); } } std::vector<std::unique_ptr<ScriptBase>> mScripts; }; class Derived : public Base { public: Derived(int x) : mX(x) {} // 加上override确保正确覆盖基类虚函数 std::unique_ptr<Base> clone() const override { // 先创建Derived实例,复制自己的成员mX auto cloned = std::make_unique<Derived>(mX); // 调用基类的辅助函数,克隆mScripts向量 copyBaseMembersTo(cloned.get()); return cloned; } private: int mX; };
这种方式的优势:
- 基类成员的克隆逻辑只写一次,所有派生类都可以复用
- 每个类只负责克隆自己的专属成员,职责清晰
- 后续新增派生类时,只需要处理自己的成员,无需重复处理基类的
mScripts
方案二:使用“先克隆基类,再补充派生类成员”的思路
另一种思路是先调用基类的clone()得到一个基类实例,然后将其转型为派生类类型,再补充派生类的成员。不过这种方式需要注意类型安全,适合简单的继承结构:
class Derived : public Base { public: Derived(int x) : mX(x) {} std::unique_ptr<Base> clone() const override { // 先调用基类clone,得到包含mScripts的Base实例 auto cloned = Base::clone(); // 转型为Derived指针(因为我们知道实际类型是Derived) auto derivedCloned = static_cast<Derived*>(cloned.get()); // 补充派生类的成员 derivedCloned->mX = mX; return cloned; } private: int mX; };
不过这种方式有个小缺点:基类的clone()创建的是Base实例,我们需要手动转型为Derived,如果后续继承层次变复杂,转型容易出错。所以更推荐第一种方案。
另外,还要提醒你几个细节:
- 所有虚函数最好加上
override关键字,避免因函数签名不一致导致的隐藏问题 - 确保
ScriptBase的clone()是纯虚函数且实现正确,否则mScripts的克隆会出问题 - 注意
unique_ptr的移动语义,你的原代码里用std::move是对的,但在范围for循环里用const auto&更安全
内容的提问来源于stack exchange,提问作者Avi
相关产品推荐
相关产品推荐

