我在C ++中定义了两个类。 Ones是基类,一个是派生类
class CBaseClass
{
…
}
class CDerivedClass : public CBaseClass
{
…
}
并希望按如下方式实现克隆功能:
CBaseClass *Clone(const CBaseClass *pObject)
{
}
当CDerivedClass的对象传递给Clone时,该函数还将创建一个CDerivedClass对象并返回。 当CBaseClass的一个对象传递给Clone时,该函数也会创建一个CBaseClass对象并返回。
如何实现这样的功能?
答案 0 :(得分:3)
虚拟克隆模式通常用于解决诸如此类的问题。经典解决方案倾向于使用clone()
方法的共变量返回类型。其他解决方案在基类和派生类之间注入工厂类型类(使用CRTP)。甚至还有一些解决方案只能通过宏实现此功能。请参阅C++ FAQ,C++ idioms和blog on this。这些解决方案中的任何一种都是可行的,最合适的取决于它们的使用环境和使用目的。
一种经典的方法,使用covariant return types并结合更现代的RAII技术(shared_ptr
等。)提供了一种非常灵活和安全的组合。协变返回类型的一个优点是,您可以在层次结构中获得与参数相同级别的克隆(即返回并不总是基类)。
该解决方案确实需要访问shared_ptr
和/或unique_ptr
。如果您的编译器不可用,boost会为这些提供替代方案。 clone_shared
和clone_unique
是根据标准库中相应的make_shared
和make_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);
}
我已添加CMoreDerivedClass
和CAnotherDerivedClass
以稍微扩展层次结构,以便更好地显示类型检查等。
答案 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
方法。