為了複製一個物件,您必須在編譯時知道該
物件的型別,因為型別是複製建構函式的“名稱”
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 的複製建構函式。
值得一提的是,這種技術利用了這樣一個事實:
編譯器在確定派生類虛方法是否重寫了具有相同名稱的基類方法時,
並不考慮函式的返回型別。
並不考慮函式的返回型別。