I define two classes in C++. Ones is the base class, and one is a derived class
    class CBaseClass
    {
    …
    }
    class CDerivedClass : public CBaseClass
    {
    …
    }
And want to implement a clone function as follows:
    CBaseClass *Clone(const CBaseClass *pObject)
    {
    }
When an object of CDerivedClass is passed to Clone, then the function will also create a CDerivedClass object and return. When an object of CBaseClass is passed to Clone, then the function will also create a CBaseClass object and return.
How to implement such a feature?
The virtual clone pattern is often used to solve problems such as these. Classic solutions tend to use co-variant return types for the clone() method. Other solution inject a factory type class (using CRTP) between the base and the derived classes. There are even solutions that just implement this functionality with macros. See the C++ FAQ, C++ idioms and a blog on this. Any one of these solutions is viable and the most appropriate would depend on the context in which they are used and intended to be used.
A classic approach, using covariant return types and coupled with more modern RAII techniques (shared_ptr et. al.) offers a very flexible and safe combination. One of the advantages of the covariant return type is that you are able to obtain a clone at the same level in the hierarchy as the argument (i.e. the return is not always to the base class).
The solution does require access to shared_ptr and/or unique_ptr. If not available with your compiler, boost provides alternatives for these. The clone_shared and clone_unique are modelled on the corresponding make_shared and make_unique utilities form the standard library. They contain explicit type checks on the class hierarchy of the arguments and target types.
#include <type_traits>
#include <utility>
#include <memory>
class CBaseClass {
public:
  virtual CBaseClass * clone() const {
    return new CBaseClass(*this);
  }
};
class CDerivedClass : public CBaseClass {
public:
  virtual CDerivedClass * clone() const {
    return new CDerivedClass(*this);
  }
};
class CMoreDerivedClass : public CDerivedClass {
public:
  virtual CMoreDerivedClass * clone() const {
    return new CMoreDerivedClass(*this);
  }
};
class CAnotherDerivedClass : public CBaseClass {
public:
  virtual CAnotherDerivedClass * clone() const {
    return new CAnotherDerivedClass(*this);
  }
};
// Clone factories
template <typename Class, typename T>
std::unique_ptr<Class> clone_unique(T&& source)
{
  static_assert(std::is_base_of<Class, typename std::decay<decltype(*source)>::type>::value,
    "can only clone for pointers to the target type (or base thereof)");
  return std::unique_ptr<Class>(source->clone());
}
template <typename Class, typename T>
std::shared_ptr<Class> clone_shared(T&& source)
{
  static_assert(std::is_base_of<Class, typename std::decay<decltype(*source)>::type>::value,
    "can only clone for pointers to the target type (or base thereof)");
  return std::shared_ptr<Class>(source->clone());
}
int main()
{
  std::unique_ptr<CDerivedClass> mdc(new CMoreDerivedClass()); // = std::make_unique<CMoreDerivedClass>();
  std::shared_ptr<CDerivedClass> cloned1 = clone_shared<CDerivedClass>(mdc);
  std::unique_ptr<CBaseClass> cloned2 = clone_unique<CBaseClass>(mdc);
  const std::unique_ptr<CBaseClass> cloned3 = clone_unique<CBaseClass>(mdc);
  // these all generate compiler errors
  //std::unique_ptr<CAnotherDerivedClass> cloned4 = clone_unique<CAnotherDerivedClass>(mdc);
  //std::unique_ptr<CDerivedClass> cloned5 = clone_unique<CBaseClass>(mdc);
  //auto cloned6 = clone_unique<CMoreDerivedClass>(mdc);
}
I've added a CMoreDerivedClass and CAnotherDerivedClass to expand the hierarchy a little to better show types checks etc.
Sample code
Here is a simple solution. Remember to provide a Clone for each class in the inheritance.
class Base
{
public:
    virtual ~Base() {}
    virtual Base *Clone() const
    {
        // code to copy stuff here
        return new Base(*this);
    }
};
class Derived : public Base
{
public:
    virtual Derived *Clone() const
    {
        // code to copy stuff here
        return new Derived(*this);
    }
};
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With