我有一个抽象基类,有几个具体的派生类。这些类都不管理任何资源。
#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/