原型模式的核心是通过虚函数clone()实现深拷贝,而非依赖指针本身;必须声明const虚clone()返回基类智能指针,子类用RAII资源管理并调用深拷贝构造。

原型模式的核心不是指针,而是拷贝逻辑
用指针实现原型模式,本质是用指针管理可克隆的对象实例,而不是靠指针本身完成“原型”语义。C++ 没有内置的 clone() 或运行时类型复制机制,必须手动定义拷贝行为——否则裸指针只会浅拷贝地址,导致悬空或重复释放。
关键判断:如果没重写虚函数 clone() 并返回新堆对象,只用 new + -> 赋值,那根本不是原型模式,只是指针传递。
必须声明虚 clone() 函数并返回基类指针
原型模式要求“通过已有对象创建新对象”,在 C++ 中最稳妥的方式是让基类提供纯虚 clone(),子类各自实现深拷贝构造:
class Prototype {
public:
virtual ~Prototype() = default;
virtual Prototype* clone() const = 0; // 关键:返回指针,支持多态
};
<p>class ConcretePrototype : public Prototype {
int<em> data<em>;
public:
ConcretePrototype(int v) : data</em>(new int(v)) {}
ConcretePrototype(const ConcretePrototype& other)
: data_(new int(</em>other.data_)) {} // 深拷贝
Prototype<em> clone() const override {
return new ConcretePrototype(</em>this); // 返回新堆对象指针
}
};-
clone()必须是const成员函数,否则无法对常量原型调用 - 返回类型必须是基类指针(如
Prototype*),不能是具体子类指针,否则破坏多态性 - 子类实现里必须调用本类的拷贝构造函数,不能只
new ConcretePrototype后逐字段赋值——否则漏掉资源管理逻辑
用智能指针替代裸指针才能避免内存泄漏
裸指针实现的 clone() 天然高危:谁 delete?什么时候 delete?一旦上层忘记清理,就是内存泄漏;重复 delete 就是崩溃。实际项目中必须用 std::unique_ptr 或 std::shared_ptr:
立即学习“C++免费学习笔记(深入)”;
class Prototype {
public:
virtual ~Prototype() = default;
virtual std::unique_ptr<Prototype> clone() const = 0;
};
<p>class ConcretePrototype : public Prototype {
std::unique<em>ptr<int> data</em>;
public:
ConcretePrototype(int v) : data_(std::make_unique<int>(v)) {}
std::unique_ptr<Prototype> clone() const override {
return std::make_unique<ConcretePrototype>(*this);
}
};- 返回
std::unique_ptr<prototype></prototype>后,调用方无需手动delete,析构自动释放 - 若需共享所有权(比如多个地方缓存同一原型副本),改用
std::shared_ptr,但要注意循环引用风险 - 不要混合使用裸指针和智能指针:比如
clone()返回unique_ptr,但外部用Prototype*接收——这会立刻丢失所有权,造成悬空
拷贝构造函数不写 = 原型失效
很多开发者以为只要写了 clone() 就行,却忘了类里有指针成员时,默认拷贝构造函数只做浅拷贝。下面这段代码看似正常,实则危险:
class BadPrototype {
int* p_;
public:
BadPrototype(int x) : p_(new int(x)) {}
// ❌ 没定义拷贝构造函数,编译器生成的版本只复制 p_ 地址
BadPrototype* clone() const { return new BadPrototype(*this); }
};此时 clone() 创建的新对象和原对象共享同一块 int 内存,任意一方析构都会让另一方指针悬空。
- 只要类内含裸指针、文件句柄、socket 描述符等需独占管理的资源,就必须显式定义拷贝构造函数(和赋值运算符)
- 现代写法优先用 RAII 类型(如
std::unique_ptr、std::vector)替代裸指针,让编译器生成的安全拷贝函数直接可用 - 如果真要用裸指针,拷贝构造里必须
new新内存,并把原值*other.p_复制过去,不能只写p_(other.p_)
原型模式在 C++ 里真正难的从来不是“怎么用指针”,而是“怎么确保每次 clone 都产生语义正确、资源独立、生命周期可控的新对象”。漏掉拷贝构造、混用指针类型、忽略 const 正确性,任何一个点出问题,整个原型链就不可靠。


















