← Patterns

Virtual constructor

1234567891011121314151617181920212223#include <memory> class Base { public: virtual ~Base() {} virtual Base* clone() const = 0; }; class Derived : public Base { public: Derived* clone() const override { return new Derived(*this); } }; void foo(std::unique_ptr<Base> original) { std::unique_ptr<Base> copy{original->clone()}; }

This pattern is licensed under the CC0 Public Domain Dedication.

Requires c++11 or newer.

Intent

Create a copy of an object through a pointer to its base type.

Description

You can’t copy an object unless you know its static type, because the compiler must know the amount of space it needs to allocate. Therefore we can’t copy an object of derived type directly through a pointer to its base.

The virtual constructor idiom is a technique for delegating the act of copying the object to the derived class through the use of virtual functions. To demonstrate, we declare a virtual member function of Base on line 8 (typically named clone) that each of the derived classes will implement to return a copy of themselves. The Derived class implements this clone function on lines 14–17, simply by creating a copy of itself and returning it.

Now, consider that we are given a std::unique_ptr<Base> on line 20 pointing to an object of derived type that we wish to copy (this could alternatively be a Base* or any other smart pointer to Base). To perform this copy, we simply call the virtual clone member function through the pointer on line 22, which thanks to polymorphism calls the Derived implementation of clone, returning a pointer that points to a copy of the original derived object.

Note: It is not possible to implement the virtual constructor idiom as-is with smart pointers, as derived virtual member functions must have covariant return types. One workaround is for Derived::clone to return a Base pointer instead. Alternatively, you can provide non-virtual wrapper functions.

Contributors

  • Joseph Mansfield
  • Tomasz Woźniak
  • Tomasz Woźniak

Last Updated

09 December 2017

Source

Fork this pattern on GitHub

Share