如何拷贝指向未知派生类的unique_ptr的内容?
如何拷贝持有无资源抽象基类的
std::unique_ptr<Base>? 你遇到的是典型的多态拷贝问题——因为std::unique_ptr<Base>指向的是派生类对象,但编译器只知道基类的接口,直接拷贝指针只会触发「对象切片」,无法完整复制派生类的内容。好在你的类都不管理资源,我们只需要给类体系添加一套克隆机制就能解决问题。
先看你的原始代码:
#include <memory> #include <vector> // 这是一个不包含资源的纯抽象类 class Base { public: Base() {}; virtual int doSomething() = 0; }; class Derived : public Base { public: Derived() {}; // 此方法会修改派生类 int doSomething() override { return 0; }; }; class Derived2 : public Base { public: Derived2() {}; // 此方法会修改派生类 int doSomething() override { return 1; }; };
解决方案:添加多态克隆方法
这是C++中实现多态拷贝的标准做法,步骤很简单:
1. 在基类中声明纯虚clone方法
给Base类新增一个返回std::unique_ptr<Base>的纯虚函数,作为克隆的入口:
class Base { public: Base() = default; // 纯虚克隆方法,要求所有派生类必须实现 virtual std::unique_ptr<Base> clone() const = 0; virtual int doSomething() = 0; // 因为类无资源,默认析构足够(若有资源则需要虚析构) virtual ~Base() = default; };
2. 在每个派生类中实现clone
每个派生类需要重写clone方法,返回自身对象的拷贝:
class Derived : public Base { public: Derived() = default; int doSomething() override { return 0; }; // 克隆当前Derived对象,包装成Base指针返回 std::unique_ptr<Base> clone() const override { return std::make_unique<Derived>(*this); } }; class Derived2 : public Base { public: Derived2() = default; int doSomething() override { return 1; }; std::unique_ptr<Base> clone() const override { return std::make_unique<Derived2>(*this); } };
3. 使用clone完成拷贝
现在你可以通过调用clone方法,轻松拷贝unique_ptr<Base>指向的任意派生类对象:
#include <iostream> int main() { std::unique_ptr<Base> ptr1 = std::make_unique<Derived>(); // 拷贝ptr1指向的Derived对象 std::unique_ptr<Base> ptr2 = ptr1->clone(); std::unique_ptr<Base> ptr3 = std::make_unique<Derived2>(); std::unique_ptr<Base> ptr4 = ptr3->clone(); std::cout << ptr1->doSomething() << std::endl; // 输出0 std::cout << ptr2->doSomething() << std::endl; // 输出0(拷贝成功) std::cout << ptr3->doSomething() << std::endl; // 输出1 std::cout << ptr4->doSomething() << std::endl; // 输出1(拷贝成功) return 0; }
为什么这个方案可行?
clone是虚函数,调用时会根据指针实际指向的派生类类型,执行对应的实现逻辑std::make_unique<Derived>(*this)会利用编译器生成的默认拷贝构造函数,完整复制当前派生类对象,再包装成unique_ptr<Base>返回,完美实现多态拷贝- 因为你的类都不管理资源,不需要手动编写拷贝构造/析构函数,编译器生成的默认版本就足够用
内容的提问来源于stack exchange,提问作者hyperdelia
相关产品推荐
相关产品推荐

