Create clone of a C++ class in polymorphic way

Introduction

Imagine we have the below class hierarchy:

struct Animal{};

struct Cat: Animal{};

struct Cow: Animal{};

In another place, we have

Animal*  a = new Cat{};

// somewhere else that we don't know
// if a is Cat or Cow
// Animal* b = /* copy of a? */

How can we make a copy of the object that a is pointing to when we don’t know the exact type of a at runtime?

To solve this we can add clone virtual function to the interface and override it in the children:


struct Animal{
    virtual ~Animal(){};
    virtual Animal* clone() const=0;
};

struct Cat: Animal{
    virtual Cat* clone () const override{
        return new Cat{*this};
    }
};

struct Cow: Animal{
    virtual Cow* clone() const override{
        return new Cow{*this};
    }
};

Now we can make clone of an object without knowing it’s a Cat or Cow:

    Animal*  a = new Cat{};
    Animal* b = a->clone();

The clone function is overridden by functions that return pointer to different types, but it still works. This is because the return types, Cat* and Cow*, are the children of Animal*. This called covariance in C++.

Clone with Unique pointer

In modern C++, we are interested in using smart pointers instead of raw pointers. It is more likely clone returns a unique pointer. Covariance technique won’t work with polymorphic functions returning unique pointers. However, the solution is as simple as before:


#include<memory>

struct Animal{
    virtual ~Animal(){};
    virtual std::unique_ptr<Animal> clone() const=0;
};

struct Cat: Animal{
    std::unique_ptr<Animal> clone () const override{
        return std::unique_ptr<Cat>(new Cat{*this});
    }
};

struct Cow: Animal{
    std::unique_ptr<Animal> clone() const override{
        return std::unique_ptr<Cow>(new Cow{*this});
    }
};

Apply it to the test case:

std::unique_ptr<Animal>  a { new Cat{33}};
std::unique_ptr<Animal> b = a->clone();

a and b point to different places in the memory that have look-alike values.

References

Covariance-wikipedia. Fluent C++ post.

Tags ➡ C++

Subscribe

I notify you of my new posts

Latest Posts

Comments

2 comments
29-Nov-2023
you are doing clone is a wrong way!
Ryan 2-Dec-2023
Beautiful, elegant and simple. Thank you!