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

时间:2014-07-24 16:47:38

标签: c++ clone

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

    class CBaseClass
    {
    …
    }

    class CDerivedClass : public CBaseClass
    {
    …
    }

并希望按如下方式实现克隆功能:

    CBaseClass *Clone(const CBaseClass *pObject)
    {
    }

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

如何实现这样的功能?

3 个答案:

答案 0 :(得分:3)

虚拟克隆模式通常用于解决诸如此类的问题。经典解决方案倾向于使用clone()方法的共变量返回类型。其他解决方案在基类和派生类之间注入工厂类型类(使用CRTP)。甚至还有一些解决方案只能通过宏实现此功能。请参阅C++ FAQC++ idiomsblog on this。这些解决方案中的任何一种都是可行的,最合适的取决于它们的使用环境和使用目的。

一种经典的方法,使用covariant return types并结合更现代的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以稍微扩展层次结构,以便更好地显示类型检查等。

Sample code

答案 1 :(得分:2)

这是一个简单的解决方案。请记住为继承中的每个类提供克隆。

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

答案 2 :(得分:0)

您可以使用虚拟Clone方法和帮助模板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方法。