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.
Latest Posts
- A C++ MPI code for 2D unstructured halo exchange
- Essential bash customizations: prompt, ls, aliases, and history date
- Script to copy a directory path in memory in Bash terminal
- What is the difference between .bashrc, .bash_profile, and .profile?
- A C++ MPI code for 2D arbitrary-thickness halo exchange with sparse blocks