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

#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; };
};


我有一个返回随机派生实例的函数(派生1,派生2,派生3,具体取决于随机数抛出)。

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

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

预先感谢所有帮助!

最佳答案

在类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引入的。当前的FAQ文本未显示。



同样值得注意的是:在C ++ 11及更高版本中,clone函数实现的生成可以通过Derived从实现继承而来,而该实现又从Base继承并转发构造函数参数,从而部分自动化。

C ++ 03不支持转发,因此必须使用一些方案,例如代码生成宏(邪恶,但实际上是当时唯一的真正解决方案),通过虚拟继承层次结构中的优势实现实现的继承(极其复杂和丑陋) ,或执行与现在在C ++ 11及更高版本中相同的操作,但具有“自己动手”参数转发方案(有点任意限制)。

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

关于c++ - 将unique_ptr的内容复制到未知的派生类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49355456/

10-13 07:25