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

ala*_*ncc 8 c++ clone

我用C++定义了两个类.Ones是基类,一个是派生类

    class CBaseClass
    {
    …
    }

    class CDerivedClass : public CBaseClass
    {
    …
    }
Run Code Online (Sandbox Code Playgroud)

并希望实现如下的克隆功能:

    CBaseClass *Clone(const CBaseClass *pObject)
    {
    }
Run Code Online (Sandbox Code Playgroud)

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

如何实现这样的功能?

Nia*_*all 6

虚拟克隆模式通常用于解决诸如此类的问题。经典解决方案倾向于为方法使用协变返回类型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);
}
Run Code Online (Sandbox Code Playgroud)

我添加了一个CMoreDerivedClassandCAnotherDerivedClass以稍微扩展层次结构以更好地显示类型检查等。

示例代码


jxh*_*jxh 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>
{
    //...
};
Run Code Online (Sandbox Code Playgroud)

现在,每个派生类都获得了Clone助手类提供的方法。