C++核心指南C.67下类层次设计:如何合理支持拷贝与移动操作?
基类拷贝禁用与移动操作的务实设计方案
咱们先把C核心指南C.67的核心逻辑捋明白:基类要禁止直接的拷贝操作,因为多态场景下拷贝基类对象会触发切片问题——只能拷贝基类部分,派生类的成员会丢失,所以正确的多态拷贝应该用virtual clone()方法来实现。但这里有个坑:如果直接把基类的拷贝构造/赋值设为删除态,C会自动隐式禁用基类和所有派生类的移动操作,可移动操作对性能提升很重要,这就得找个务实的平衡方案。
一、核心设计思路
- 基类层面:严格禁止值语义的拷贝(删除拷贝构造和拷贝赋值),但显式启用移动操作(默认化移动构造和赋值)——移动操作不会导致切片,而且能高效转移资源。
- 提供
virtual clone()纯虚方法,让派生类重写,以此实现安全的多态拷贝。 - 派生类层面:实现自己的拷贝构造/赋值(因为基类拷贝被删,派生类默认拷贝会被禁用),同时默认化移动操作,确保自身成员能正确拷贝/移动。
二、修改后的类A和B实现
#include <string> #include <vector> class A { public: // 1. 删除拷贝构造和赋值,彻底禁止值语义拷贝 A(const A&) = delete; A& operator=(const A&) = delete; // 2. 显式默认移动构造和赋值,保留移动能力 A(A&&) = default; A& operator=(A&&) = default; // 3. 多态拷贝的核心:纯虚clone方法 virtual A* clone() const = 0; // 可用的构造函数(原代码把构造删了,根本没法创建对象,必须补上) explicit A(std::string as) : s(std::move(as)) {} virtual void foo() = 0; // 虚析构必须有,保证派生类能正确析构 virtual ~A() = default; protected: // 给派生类提供访问基类成员的接口,方便派生类实现拷贝 const std::string& get_s() const { return s; } void set_s(std::string new_s) { s = std::move(new_s); } private: std::string s; }; class B : public A { public: // 派生类构造:调用基类构造初始化基类成员 explicit B(std::string as, std::vector<std::string> v) : A(std::move(as)), vs(std::move(v)) {} // 重写clone方法,返回派生类指针(协变返回类型) B* clone() const override { return new B(*this); // 这里用派生类自己的拷贝构造,安全无切片 } // 手动实现拷贝构造:基类拷贝被删,默认拷贝构造会被禁用 B(const B& other) : A(other.get_s()), vs(other.vs) {} // 手动实现拷贝赋值 B& operator=(const B& other) { if (this != &other) { set_s(other.get_s()); // 用基类的protected接口更新基类成员 vs = other.vs; } return *this; } // 默认化移动构造和赋值,利用编译器生成的高效实现 B(B&&) = default; B& operator=(B&&) = default; void foo() override {} ~B() override = default; private: std::vector<std::string> vs; };
三、关键细节解析
- 显式启用基类移动:C++的规则是,如果类有删除的拷贝操作,移动操作会被隐式删除,所以必须显式写
= default来保留移动能力,这样派生类才能继承并使用移动操作。 - clone方法的协变返回:派生类的
clone可以返回B*而不是A*,这是C++允许的协变返回类型,能让用户在拿到克隆对象时直接使用派生类的接口,不用额外转换。 - 派生类拷贝的实现:因为基类的拷贝被删除,派生类的默认拷贝构造/赋值会被禁用,所以必须手动实现,通过基类提供的protected接口来访问基类成员,完成完整的拷贝。
- 构造函数的修正:原代码中A的构造被设为删除态,这会导致根本无法创建A或B的对象,所以必须提供可用的构造函数,同时用
std::move来优化字符串的传递,避免不必要的拷贝。
内容的提问来源于stack exchange,提问作者pchrys
相关产品推荐
相关产品推荐

