问题
When a class has a unique_ptr of a Base class what is a good way to implement the copy constructor.
Let me try to explain it with an example:
struct Base
{
virtual void doSth() = 0; // to make the class abstract.
};
struct Derived : public Base
{
virtual void doSth() override {}
};
struct Foo
{
std::unique_ptr<Base> bar;
Foo(const Foo& other) : bar(new Base(*other.bar)) // cant do it, its abstract.
{
bar = std::move(other.bar); // cant do it, reference object is modified.
}
};
Here as the class is abstract i cannot use its copy constructor. and also cannot use move on a constant reference ( we shouldnt do it actually, do not modify the object).
What I end up with is like so:
struct Base
{
virtual void doSth() = 0; // to make the class abstract.
};
struct Derived : public Base
{
virtual void doSth() override {}
Derived(const Base* b)
{
}
};
struct Foo
{
std::unique_ptr<Base> bar;
Foo(const Foo& other) : bar(new Derived(other.bar.get()))
{
}
};
However, it does not feel quite right, does it?
回答1:
If you need to copy polymorphically, you will need to provide that in the interface of the type you are holding. Add a clone
virtual function to Base
and use that to create a copy that you can store in the copied Foo
.
Other alternatives include not copying (delete the copy constructor) or use reference semantics (copies refer to the same object: change unique_ptr
for shared_ptr
) but neither of those alternatives really provide copies.
回答2:
Here is the code for David's answer. Note that the virtual clone()
is described in this answer.
#include <stdlib.h>
#include <cstddef>
#include <memory>
struct Base
{
virtual void doSth() = 0; // to make the class abstract.
virtual Base* clone() const = 0;
};
struct Derived : public Base
{
virtual void doSth() override {}
virtual Derived* clone() const {
return new Derived(*this);
}
};
struct Foo
{
std::unique_ptr<Base> bar;
Foo(const Foo& other) : bar(other.bar->clone()) // cant do it, its abstract.
{
}
};
来源:https://stackoverflow.com/questions/23717967/copy-constructor-for-a-class-that-has-unique-ptr-of-a-base-class