如何在C++; 我定义C++中的两个类。一个是基类,一个是派生类 class CBaseClass { … } class CDerivedClass : public CBaseClass { … }

如何在C++; 我定义C++中的两个类。一个是基类,一个是派生类 class CBaseClass { … } class CDerivedClass : public CBaseClass { … },c++,clone,C++,Clone,并希望实现如下克隆功能: CBaseClass *Clone(const CBaseClass *pObject) { } 当CDerivedClass的对象传递给Clone时,该函数还将创建CDerivedClass对象并返回。 当CBaseClass的对象传递给Clone时,该函数还将创建CBaseClass对象并返回 如何实现此功能?您可以通过虚拟克隆方法和帮助器模板CRTP类来实现此接口: class CBaseClass { //... vir

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

    CBaseClass *Clone(const CBaseClass *pObject)
    {
    }
当CDerivedClass的对象传递给Clone时,该函数还将创建CDerivedClass对象并返回。 当CBaseClass的对象传递给Clone时,该函数还将创建CBaseClass对象并返回


如何实现此功能?

您可以通过虚拟克隆方法和帮助器模板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>
{
    //...
};
class-cbase类{
//...
虚拟CBaseClass*克隆()=0;
std::unique_ptr UniqueClone(){
返回std::unique_ptr(Clone());
}
虚拟std::shared_ptr SharedClone()=0;
};
模板
CBaseClassCRTP类:公共CBaseClass类
{
CBaseClass*克隆(){
返回新的派生(*static_cast(this));
}
std::shared_ptr SharedClone(){
返回std::make_shared(*static_cast(this));
}
};
类别CDerivedClass:公共CBaseClassCRTP
{
//...
};

现在,每个派生类都获得了helper类提供的克隆方法。

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

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()
方法使用同变量返回类型。另一种解决方案是在基类和派生类之间注入工厂类型类(使用CRTP)。甚至有一些解决方案只是通过宏实现此功能。看到了,还有一个。这些解决方案中的任何一个都是可行的,最合适的解决方案将取决于使用和打算使用它们的环境

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

解决方案确实需要访问
共享的\u ptr
和/或
唯一的\u ptr
。如果您的编译器不支持,boost会提供这些选项。
clone\u shared
clone\u unique
以标准库中相应的
make\u shared
make\u 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);
}
#包括
#包括
#包括
类CBASE类{
公众:
虚拟CBaseClass*克隆()常量{
返回新的CBaseClass(*此);
}
};
类别CDerivedClass:公共CBaseClass{
公众:
虚拟CDerivedClass*克隆()常量{
返回新的CDerivedClass(*此);
}
};
类别CMoreDerivedClass:公共CDerivedClass{
公众:
虚拟CMoreDerivedClass*克隆()常量{
返回新的CMoreDerivedClass(*此);
}
};
类别CAnotherDerivedClass:公共CBase类别{
公众:
虚拟CAnotherDerivedClass*克隆()常量{
返回新的CAnotherDerivedClass(*本);
}
};
//克隆工厂
模板
std::unique\u ptr clone\u unique(T&&source)
{
static_assert(std::是::value的_base_),
“只能克隆指向目标类型(或其基类型)的指针”;
返回std::unique_ptr(source->clone());
}
模板
std::shared\u ptr clone\u shared(T&&source)
{
static_assert(std::是::value的_base_),
“只能克隆指向目标类型(或其基类型)的指针”;
返回std::shared_ptr(source->clone());
}
int main()
{
std::unique_ptr mdc(新的CMoreDerivedClass());/=std::make_unique();
std::shared_ptr cloned1=clone_shared(mdc);
std::unique_ptr cloned2=克隆_unique(mdc);
const std::unique_ptr cloned3=clone_unique(mdc);
//这些都会生成编译器错误
//std::unique_ptr cloned4=克隆_unique(mdc);
//std::unique_ptr cloned5=克隆_unique(mdc);
//auto cloned6=克隆唯一(mdc);
}
我添加了一个
CMoreDerivedClass
CAnotherDerivedClass
,以稍微扩展层次结构,更好地显示类型检查等


虚拟成员函数
clone
如何?
clone
应该是由您层次结构中的每个类实现的虚拟成员方法,包括
CDerivedClass
如果您有一个基指针并且不知道确切的类型,可能会发生什么情况?您应该返回
DERIVED*
dynamic\u cast
是不必要的,您应该在此处使用智能指针。必须将要克隆的对象传递到克隆函数中似乎有些奇怪。我习惯于这样调用克隆:
cloned\u object=some\u object.clone()
。您要克隆的东西将由
std::unique\u ptr
管理,这似乎很奇怪;它大概是在克隆之后完成的,不需要任何进一步的管理。@Puppy协变返回与unique_ptr不兼容,所以我放弃了。如果你有更好的解决方案,请告诉我。@NeilKirk:你唯一需要克隆的时候是当你不知道最派生的类型时,因此,简单地返回一个我能想到的
std::unique_ptr
并没有什么坏处。在这里使用协变返回有什么好处?@Puppy克隆时,你到底为什么不使用原始指针?你为什么要用CRTP让工作超负荷?第一个可能是设计错误,CRTP只是不必要的额外复杂性。我同意Mooning Duck的观点,它们应该与
unique\u ptr
无关,但如果协变返回很重要,您可以创建一个
make
样式,类似于
make\u unique
,立即将其绑定到所需的
唯一\u ptr
的工厂。您需要调用
make\u shared
,以避免克隆共享指针时的内存分配开销。@jxh,这一点很好<代码>使_共享尽管创建对象