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

标签 c++ clone

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

    class CBaseClass
    {
    …
    }

    class CDerivedClass : public CBaseClass
    {
    …
    }

并且想实现一个克隆函数如下:

    CBaseClass *Clone(const CBaseClass *pObject)
    {
    }

当一个CDerivedClass对象被传递给Clone时,那么这个函数也会创建一个CDerivedClass对象并返回。 当一个 CBaseClass 对象被传递给 Clone 时,该函数也会创建一个 CBaseClass 对象并返回。

如何实现这样的功能?

最佳答案

虚拟克隆模式经常被用来解决诸如此类的问题。经典解决方案倾向于为 clone() 方法使用协变返回类型。其他解决方案在基类和派生类之间注入(inject)工厂类型类(使用 CRTP)。甚至还有仅使用宏来实现此功能的解决方案。查看C++ FAQ , C++ idioms和一个 blog 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

关于c++ - 如何在 C++ 中克隆为派生对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24939570/

相关文章:

rust - std::iter::FlatMap.clone() 可能吗?

C++:如何使用时间和本地时间获取实际时间?

java - 如何复制 java.util.list 集合

git - 从 git 存储库克隆时出现 TLS 错误

java - 克隆字符串数组,检查引用

javascript - 对克隆表单进行验证

时间:2019-03-08 标签:c++overload[]operator

c++ - 将 ADA API 公开给 C/C++(可扩展方式)

c++ - 从文件中读取未知长度的字符串

c++ - 多线程可以访问同一个weak_ptr对象C++