为了复制一个对象,您必须在编译时知道该
对象的类型,因为类型是复制构造函数的“名称”
1 2 3 4
|
void copy_me( const std::string& s ) {
std::string s_copy( s );
std::string* p_s_copy = new std::string( s );
}
|
我知道在编译时 s 的类型是“std::string”,因为它在参数列表中
明确说明了。但如果 s 的类型是基类呢?
1 2 3 4 5 6
|
class Base {};
class Derived : public Base {};
void copy_me( const Base& b ) {
Base b_copy( b ); // ????
}
|
这并不完全奏效,因为我可以用派生类实例调用 copy_me(),
在这种情况下,该函数将希望实例化一个 Derived 对象,而不是一个 Base 对象。
但在编译时,我根本无法知道这一点。事实上,我甚至可以在一个地方用 Base 实例调用 copy_me(),
在另一个地方用 Derived 实例调用,在第三个地方用派生自 Base 或 Derived 的其他东西调用。
在另一个地方用 Derived 实例调用,在第三个地方用派生自 Base 或 Derived 的其他东西调用。
在第三个地方用派生自 Base 或 Derived 的其他东西调用。
这个问题如何解决?
克隆模式正是为此目的而实现的。克隆模式如下所示
克隆模式如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
// Depending upon your needs, you might not require a base class
// clonable concept. It would only be needed if you need to store
// clonable objects polymorphically.
struct clonable {
virtual ~clonable() {}
virtual clonable* clone() const = 0;
};
class Base : public clonable {
public:
virtual Base* clone() const
{ return new Base( *this ); }
};
class Derived : public Base {
public:
virtual Derived* clone() const
{ return new Derived( *this ); }
};
|
现在,copy_me 看起来是这样的
1 2 3 4
|
void copy_me( const Base& b ) {
Base* clone = b.clone();
// delete clone;
};
|
如果 b 的“真实类型”是 Base,我就成功调用了 Base 的复制构造函数,
如果 b 的“真实类型”是 Derived,我就成功调用了 Derived 的复制构造函数。
如果 b 的“真实类型”是 Derived,我就成功调用了 Derived 的复制构造函数。
值得一提的是,这种技术利用了这样一个事实:
编译器在确定派生类虚方法是否重写了具有相同名称的基类方法时,
并不考虑函数的返回类型。
并不考虑函数的返回类型。