如何在c++中克隆为派生对象
How to clone as derived object in C++
在c++中定义了两个类。一个是基类,一个是派生类
class CBaseClass
{
…
}
class CDerivedClass : public CBaseClass
{
…
}
并希望实现如下的克隆函数:
CBaseClass *Clone(const CBaseClass *pObject)
{
}
当CDerivedClass的对象传递给Clone时,该函数也将创建CDerivedClass对象并返回。当CBaseClass的对象传递给Clone时,该函数也将创建一个CBaseClass对象并返回。
如何实现这样的功能?
虚拟克隆模式通常用于解决诸如此类的问题。经典的解决方案倾向于对clone()
方法使用协变返回类型。其他解决方案在基类和派生类之间注入工厂类型类(使用CRTP)。甚至有一些解决方案只用宏来实现这个功能。请参阅c++常见问题解答、c++习惯用法和有关这方面的博客。这些解决方案中的任何一个都是可行的,并且最合适的解决方案将取决于使用它们和打算使用它们的上下文。
使用协变返回类型并结合更现代的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
来扩展层次结构,以便更好地显示类型检查等。
这里有一个简单的解决方案。记住为继承中的每个类提供一个Clone。
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方法和一个helper模板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
方法,这是由helper类提供的。
- 为什么此派生对象无法访问基类的后递减方法?
- 如何在新的派生对象中获取基本对象的数据?
- 如何将成员函数作为参数传递并在派生对象上执行方法列表
- 在没有默认构造函数的情况下创建的派生对象
- OOP 标识派生对象
- 如何创建派生对象的向量?
- 将基类分配给派生对象,反之亦然,以C++以及静态和动态对象之间的差异
- 如何从 Gtk::窗口调用派生对象的析构函数
- 无法在派生对象上运行虚拟函数
- 尝试删除指向派生对象的基指针时断言错误
- 存储在一个通用容器中的派生对象.如何避免铸造
- 将派生对象分配给函数内的基类指针
- 替换派生对象向量中的对象"no matching function to call"
- 派生对象调用的 Base 方法的模板推导
- 用于填充 Base 和派生对象的 shared_ptr 向量的函数模板
- C++ UBSAN 对派生对象产生误报
- 如何验证我是否正在使用C++中的基对象或派生对象
- C++ 构造函数和派生对象
- 将派生对象传递给模板
- 指向派生作品的基本指针,即使派生对象不存在