将unique_ptr的内容复制到未知的派生类

时间:2018-03-19 03:38:37

标签: c++

我有一个抽象的基类,有几个具体的派生类;这些类都不管理任何资源。

#include <memory>
#include <vector>

// this is a pure abstract class that contains no resources
class Base {
public:
    Base() {};
    virtual int doSomething() = 0;
};

class Derived : public Base {
public:
    Derived()  {};

    // this mutates the derived class
    int doSomething() override { return 0; };
};

class Derived2 : public Base {
public:
    Derived2() {};

    // this mutates the derived class
    int doSomething() override { return 0; };
};

我有一个函数返回一个随机派生的实例(Derived1,Derived2,Derived3,取决于随机数抛出)。

std::unique_ptr<Base> randomDerivedInstance() {
    // pick a random number here and return Derived1 or Derived2 etc.
    // for the purpose of this problem, I'm just returning a fixed derived class
    return std::make_unique<Derived>();
}

我有一个结构,我想将此派生实例存储在

struct DataStruct {

    // this can contain Derived1 or Derived2
    std::unique_ptr<Base> base;

    // other things in struct omitted for clarity

    // obviously this won't work
    DataStruct(std::unique_ptr<Base> base) : base(base) {};
};

我从随机函数返回一个唯一的指针,并希望将一个副本保存到结构中,然后在其上调用doSomething,对类内部执行多个变异操作,我不想要它们影响存储在列表中的副本。

如果我知道派生实例的类型,我会使用复制构造函数来创建一个新实例并将其添加到向量中,但在这种情况下我不知道我正在尝试的实例的具体类型添加,所以我不知道使用哪个具体的构造函数。

int main() {
    // I want to create a vector of random instances
    std::vector<DataStruct> list;

    // I create a random instance
    auto myDerived = randomDerivedInstance();

    // and I want to push a copy of myDerived before I do something with it
    // obviously this doesn't work because its a unique_ptr
    // what can I do here?
    list.push_back(DataStruct(myDerived));

    // do something that mutates myDerived
    myDerived->doSomething();

    // I don't want my mutations to myDerived to affect the list copy


}

由于我试图在unique_ptr构造函数中分配DataStruct,上面的代码由于显而易见的原因而无法编译。

我需要对此架构和代码进行哪些更改才能使其按预期工作?即将随机派生实例的值副本添加到结构中,以便我可以改变原始实例(反之亦然,添加原始实例和变异副本)。

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

在课程Base中添加虚拟成员函数clone

virtual auto clone() const
    -> std::unique_ptr<Base>
    = 0;

在每个派生类Derived中重写以提供派生类特定克隆:

auto clone() const
    -> std::unique_ptr<Base>
    override
{ return std::unique_ptr<Base>( new Derived{ *this } ); }

可以以更高级的方式执行此操作,如果您在编译时知道派生类最多的类,则可以静态获取该类型的克隆,但似乎不需要它。

免责声明:袖珍代码,未经编译器审核。

很久以前,clone函数被称为虚拟构造函数,该术语在the FAQ item about this中使用。我认为它是由Coplien介绍的。目前的常见问题解答文本没有说明。

另外值得注意的是:在C ++ 11及更高版本中clone函数实现的生成可以部分自动化Derived继承自实现的实现,而实现继承自Base,转发构造函数参数。

C ++ 03不支持转发,因此必须使用代码生成宏(恶意但实际上是当时唯一真正的解决方案)等方案,通过虚拟继承层次结构中的支配实现继承(极其复杂) (或丑陋),或者像我们现在在C ++ 11及更高版本中所做的那样,但是使用自己动手的参数转发方案(有些任意限制)。

有关这些旧C ++ 03技术的概述,请参阅我的2010年博客文章“3 ways to mix in a generic cloning implementation”。