更多 C++ 習語/虛擬建構函式
在不知道其具體型別的情況下建立物件的副本或新物件。
初始化的工廠方法
在面向物件程式設計社群中,在類層次結構中多型呼叫成員函式的使用是眾所周知的。它是實現is-a(或更實際地說,behaves-as-a)關係的一種方法。有時,多型呼叫類層次結構的生命週期管理(建立、複製和銷燬)函式很有用。
C++ 本身使用虛擬解構函式支援物件的 多型銷燬。但缺少對物件建立和複製的等效支援。在 C++ 中,物件的建立始終需要在編譯時知道其型別。虛擬建構函式習語允許在 C++ 中多型建立和複製物件。
create() 成員函式用於建立和 clone() 成員函式用於複製構造的效果,如下所示。
class Employee
{
public:
virtual ~Employee () {} // Native support for polymorphic destruction.
virtual Employee * create () const = 0; // Virtual constructor (creation)
virtual Employee * clone () const = 0; // Virtual constructor (copying)
};
class Manager : public Employee // "is-a" relationship
{
public:
Manager (); // Default constructor
Manager (Manager const &); // Copy constructor
virtual ~Manager () {} // Destructor
Manager * create () const // Virtual constructor (creation)
{
return new Manager();
}
Manager * clone () const // Virtual constructor (copying)
{
return new Manager (*this);
}
};
class Programmer : public Employee { /* Very similar to the Manager class */ };
Employee * duplicate (Employee const & e)
{
return e.clone(); // Using virtual constructor idiom.
}
Manager 類實現兩個純虛擬函式,並使用型別名稱 (Manager) 建立它們。duplicate 函式展示了虛擬建構函式習語的使用方式。它實際上不知道它在複製什麼。它只知道它在克隆一個 Employee。建立正確例項的責任被委託給派生類。因此,即使以 Employee 為根的類層次結構將來添加了更多子類,duplicate 函式也對修改關閉。
Manager 類的 clone 和 create 成員函式的返回型別不是 Employee,而是類本身。C++ 允許在型別方面具有這種靈活性,其中重寫函式的返回型別可以是基類中函式的派生型別。這種語言特性稱為協變返回型別。
為了正確處理資源所有權,應該對 clone() 和 create() 函式的返回型別使用資源返回習語,因為它們是工廠函式。如果使用,返回型別 (shared_ptr<Employee> 和 shared_ptr<Manager>) 將不再是協變返回型別,程式將無法編譯。在這種情況下,派生類中的虛擬建構函式應該返回與父類中相同的精確型別。
#include <tr1/memory>
class Employee
{
public:
typedef std::tr1::shared_ptr<Employee> Ptr;
virtual ~Employee () {} // Native support for polymorphic destruction.
virtual Ptr create () const = 0; // Virtual constructor (creation)
virtual Ptr clone () const = 0; // Virtual constructor (copying)
};
class Manager : public Employee // "is-a" relationship
{
public:
Manager () {} // Default constructor
Manager (Manager const &) {} // Copy constructor
virtual ~Manager () {}
Ptr create () const // Virtual constructor (creation)
{
return Ptr(new Manager());
}
Ptr clone () const // Virtual constructor (copying)
{
return Ptr(new Manager (*this));
}
};
std::function