If one wants to implement Clone
pattern in C++, he might not be sure about safety, because derived class may forget to override it:
struct A {
virtual A* Clone() const {
return new A(*this);
}
}
struct B : A {
int value;
};
int main() {
B b;
// oops
auto b_clone = b.Clone();
delete b_clone;
}
What are the possible ways to improve Clone
pattern in C++ in this regard?
A more general question has been asked: Forcing a derived class to overload a virtual method in a non-abstract base class
However, it seems to be too general to have a good solution in C++ -- the discussion is about possible ways to enforce method override. I'm more interested in discovering a useful pattern, which might help in the exact case of using Cloneable pattern.
This is an elaboration of one of the answers, suggesting runtime check using typeid: Forcing a derived class to overload a virtual method in a non-abstract base class
Using CRTP, one can come up with the following basic idea:
Create class Cloneable<Derived>
, which manages cloning for Derived
, and adds all the needed runtime checks (seems like that compile-time checks are not possible even with CRTP).
However, it is not trivial, and one also has to manage inheritance through Cloneable
, as described:
#include <memory>
#include <cassert>
#include <type_traits>
#include <typeinfo>
class CloneableInterface {
public:
virtual std::unique_ptr<CloneableInterface> Clone() const = 0;
};
template <class... inherit_from>
struct InheritFrom : public inherit_from... {
};
template <class Derived, class AnotherBase = void, bool base_is_cloneable = std::is_base_of_v<CloneableInterface, AnotherBase>>
class Cloneable;
// three identical implementations, only the inheritance is different
// "no base is defined" case
template <class Derived>
class Cloneable<Derived, void, false> : public CloneableInterface {
public:
std::unique_ptr<CloneableInterface> Clone() const override {
assert(typeid(*this) == typeid(Derived));
return std::make_unique<Derived>(static_cast<const Derived&>(*this));
}
};
// Base is defined, and already provides CloneableInterface
template <class Derived, class AnotherBase>
class Cloneable<Derived, AnotherBase, true> : public AnotherBase {
...
};
// Base is defined, but has no CloneableInterface
template <class Derived, class AnotherBase>
class Cloneable<Derived, AnotherBase, false> : public AnotherBase, public CloneableInterface {
...
};
Usage example:
class Base : public Cloneable<Base> {
};
// Just some struct to test multiple inheritance
struct Other {
};
struct Derived : Cloneable<Derived, InheritFrom<Base, Other>> {
};
struct OtherBase {
};
struct OtherDerived : Cloneable<OtherDerived, InheritFrom<OtherBase>> {
};
int main() {
// compiles and runs
auto base_ptr = std::make_unique<Base>();
auto derived_ptr = std::make_unique<Derived>();
auto base_clone = base_ptr->Clone();
auto derived_clone = derived_ptr->Clone();
auto otherderived_ptr = std::make_unique<OtherDerived>();
auto otherderived_clone = otherderived_ptr->Clone();
}
Any critics and improvement suggestions are welcome!