这(如果我理解正确的话)被称为 ¹克隆。只需在基类中添加一个虚拟的clone 成员函数即可。在每个具体派生类中覆盖它。
核心功能示例:
class Base
{
private:
// Whatever
public:
virtual auto clone() const
-> Base*
{ return new Base( *this ); }
virtual ~Base() {}
};
class Derived_A
: public Base
{
public:
auto clone() const
-> Derived_A* // OK, covariant return type.
override
{ return new Derived_A( *this ); }
};
#include <assert.h>
#include <typeinfo>
auto main()
-> int
{
Base const& o = Derived_A{};
auto p = o.clone();
assert( typeid( *p ) == typeid( Derived_A ) );
delete p; // ← Manual cleanup is a problem with basic cloning.
}
用返回Derived_A* 而不是一般的Base* 的函数覆盖clone 函数是可以的,因为它是一个原始指针并且结果类型是协变的(在更具体的类中更具体,即在 与类特异性相同的方式)。对于原始参考,它也可以很好地工作。但是 C++ 不直接支持类类型函数结果,包括智能指针作为 clone 函数结果。
正如评论所指出的,直接简单克隆的一个问题是清理责任不明确。最好有自动化和有保证的,但随后就会遇到不支持协变智能指针的问题。令人高兴的是,可以“手动”实现协方差,方法是使虚拟 clone 函数成为非 public,并在每个类中提供特定于类的智能指针结果包装函数。
具有协变智能指针结果的克隆示例:
#include <memory> // std::unique_ptr
class Base
{
private:
// Whatever, and
virtual auto virtual_clone() const
-> Base*
{ return new Base( *this ); }
public:
auto clone() const
{ return std::unique_ptr<Base>( virtual_clone() ); }
virtual ~Base() {}
};
class Derived_A
: public Base
{
private:
auto virtual_clone() const
-> Derived_A* // OK, covariant return type.
override
{ return new Derived_A( *this ); }
public:
auto clone() const
{ return std::unique_ptr<Derived_A>( virtual_clone() ); }
};
#include <assert.h>
#include <typeinfo>
auto main()
-> int
{
Base const& o = Derived_A{};
auto p = o.clone();
assert( typeid( *p ) == typeid( Derived_A ) );
// Automatic cleanup.
}
这是一种在Base 和Derived_A 中自动生成克隆支持机制的方法,基于中间人继承的概念:
#include <memory> // std::unique_ptr
#include <utility> // std::forward
// Machinery:
template< class Derived_t >
class With_base_cloning_
{
private:
auto virtual virtual_clone() const
-> Derived_t*
{ return new Derived_t( *static_cast<Derived_t const*>( this ) ); }
public:
auto clone() const
{ return std::unique_ptr<Derived_t>( virtual_clone() ); }
virtual ~With_base_cloning_() {}
};
template< class Derived_t, class Base_t >
class With_cloning_
: public Base_t
{
private:
auto virtual_clone() const
-> Base_t* // Ungood type because Derived_t is incomplete here.
override
{ return new Derived_t( *static_cast<Derived_t const*>( this ) ); }
public:
auto clone() const
{ return std::unique_ptr<Derived_t>( static_cast<Derived_t*>( virtual_clone() ) ); }
template< class... Args >
With_cloning_( Args... args )
: Base_t( std::forward<Args>( args )... )
{}
};
你会这样使用它:
// Usage example:
class My_base
: public With_base_cloning_<My_base>
{};
class Derived_A
: public With_cloning_<Derived_A, My_base>
{};
#include <assert.h>
#include <typeinfo>
auto main()
-> int
{
My_base const& o = Derived_A{};
auto p = o.clone();
assert( typeid( *p ) == typeid( Derived_A ) );
// Automatic cleanup.
}
With_cloning_ 中的(私有)virtual_clone 函数的返回类型并不是我们想要的,并不理想,因为在模板实例化的那一刻派生类还没有完成,所以编译器没有'还不知道它是从模板实例化派生的。
这种中间人继承解决方案的替代方案,包括一个简单的代码生成宏,以及在虚拟继承层次结构中的(复杂)支配地位。
¹ 一个clone 函数,在底部调用最派生类的复制构造函数,是virtual constructor idiom 的一种特殊情况。另一个特殊情况是create 函数,它在底部调用最派生类的默认构造函数。