如何在c++中克隆为派生对象

How to clone as derived object in C++

本文关键字:派生 对象 c++      更新时间:2023-10-16

在c++中定义了两个类。一个是基类,一个是派生类

    class CBaseClass
    {
    …
    }
    class CDerivedClass : public CBaseClass
    {
    …
    }

并希望实现如下的克隆函数:

    CBaseClass *Clone(const CBaseClass *pObject)
    {
    }

当CDerivedClass的对象传递给Clone时,该函数也将创建CDerivedClass对象并返回。当CBaseClass的对象传递给Clone时,该函数也将创建一个CBaseClass对象并返回。

如何实现这样的功能?

虚拟克隆模式通常用于解决诸如此类的问题。经典的解决方案倾向于对clone()方法使用协变返回类型。其他解决方案在基类和派生类之间注入工厂类型类(使用CRTP)。甚至有一些解决方案只用宏来实现这个功能。请参阅c++常见问题解答、c++习惯用法和有关这方面的博客。这些解决方案中的任何一个都是可行的,并且最合适的解决方案将取决于使用它们和打算使用它们的上下文。

使用协变返回类型并结合更现代的RAII技术(shared_ptr等)的经典方法提供了非常灵活和安全的组合。协变返回类型的优点之一是,您可以在层次结构中获得与参数相同级别的克隆(即返回并不总是对基类)。

解决方案确实需要访问shared_ptr和/或unique_ptr。如果编译器不能提供这些选项,boost提供了替代选项。clone_sharedclone_unique是基于标准库中相应的make_sharedmake_unique实用程序建模的。它们包含对参数和目标类型的类层次结构的显式类型检查。

#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);
}

我添加了CMoreDerivedClassCAnotherDerivedClass来扩展层次结构,以便更好地显示类型检查等。

样例代码

这里有一个简单的解决方案。记住为继承中的每个类提供一个Clone。

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);
    }
};

您可以使用一个虚拟Clone方法和一个helper模板CRTP类来实现此接口:

class CBaseClass {
    //...
    virtual CBaseClass * Clone () = 0;
    std::unique_ptr<CBaseClass> UniqueClone () {
        return std::unique_ptr<CBaseClass>(Clone());
    }
    virtual std::shared_ptr<CBaseClass> SharedClone () = 0;
};
template <typename DERIVED>
class CBaseClassCRTP : public CBaseClass
{
    CBaseClass * Clone () {
        return new DERIVED(*static_cast<DERIVED *>(this));
    }
    std::shared_ptr<CBaseClass> SharedClone () {
        return std::make_shared<CbaseClass>(*static_cast<DERIVED *>(this));
    }
};
class CDerivedClass : public CBaseClassCRTP<CDerivedClass>
{
    //...
};

现在,每个派生类都有一个Clone方法,这是由helper类提供的。