更多 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