I have Base
and Derived
classes that I need polymorphic behaviour from, via the virtual member function foo()
:
#include <iostream>
#include <memory>
class Base {
public:
virtual int foo() const = 0;
};
class Derived : public Base {
public:
int foo() const override { return 42; }
};
std::unique_ptr<Base> clone(Base & base) {
//auto copy = base; // cannot create an abstract type
//return std::make_unique(copy);
return std::make_unique(base);
}
int main() {
auto d = Derived();
auto p = clone(d);
std::cout << p->foo() << '\n';
}
Does not compile: https://godbolt.org/z/voaGdf1sM
<source>: In function 'std::unique_ptr<Base> clone(Base&)':
<source>:19:28: error: no matching function for call to 'make_unique(Base&)'
19 | return std::make_unique(base);
| ~~~~~~~~~~~~~~~~^~~~~~
Outside of clone()
, I want to be able to treat instances of Derived
with value semantics throughout most of the program, but there is a case where I need to add instances of Derived
to a collection (std::vector<std::unique_ptr<Base>>
) and retain polymorphism, so in this case I need to be able to add unique_ptr
s to new copies of the Derived
objects. Thus I have the function clone()
which takes a reference to a Derived
object and is intended to make a copy that is then owned by a unique_ptr
, and this is returned.
Unfortunately I cannot work out how to make a polymorphic copy of a reference to an abstract type like Base
.
I cannot pass the parameter by value, and then move the implicit copy into the unique_ptr
, as it's not possible to have an instance of Base
, and I need the polymorphism.
I looked into using a forwarding reference, something like:
std::unique_ptr<Base> clone(Base && base) {
return std::make_unique(base);
}
// ...
auto p = clone(std::move(d));
But I don't want to expose the ownership at the caller and require them to call std::move
- it should be free to pass in a reference to an existing object and expect clone
to copy it, not take ownership of it. I actually want it to be copied, and for the source object to remain intact and able to be used again (e.g. to make more copies).
Note: if I could get this working, it would probably be better for clone
to take a const Base &
, as I'm passing by reference for performance reasons after all.
Is what I'm trying to do here - make a copy, that is managed as a unique_ptr
, without imposing move semantics on the caller - even possible?