The typical pattern when you want to copy a polymorphic class is adding a virtual clone method and implement it in each derived class like this:
Base* Derive
If you can control how you pass around the polymorphic type, use type erasure. In particular, the proposed std::polymorphic_value calls the derived copy constructor when it is copied. You can imagine it as something like this:
template
class polymorphic_value {
public:
template >::value, int> = 0>
explicit polymorphic_value(D&& value)
: ptr{std::make_unique>>(std::forward(value))}
{}
polymorphic_value(polymorphic_value const& rhs)
: ptr{rhs.ptr->clone()}
{}
B const& get() const { return ptr->get(); }
B& get() {
// Safe usage of const_cast, since the actual object is not const:
return const_cast(ptr->get());
}
private:
struct base_t {
virtual ~base_t() = default;
virtual std::unique_ptr clone() const = 0;
// With more effort, this doesn't have to be a virtual function.
// For example, rolling our own vtables would make that possible.
virtual B const& get() const = 0;
};
template
struct derived_t final : public base_t {
explicit derived_t(D const& d)
: value{d}
{}
explicit derived_t(D&& d)
: value{std::move(d)}
{}
std::unique_ptr clone() const override {
return std::make_unique(value);
}
B const& get() const override {
return value;
}
D value;
};
std::unique_ptr ptr;
};
For a thorough implementation which follows the proposal, see jbcoe's github repository.
Sample usage:
class Base {
public:
virtual ~Base() = default;
};
class Derived : public Base {
public:
Derived() = default;
Derived(Derived const&);
};
int main() {
polymorphic_value it{Derived{}};
auto const copy = it;
}
Live on Godbolt