我们知道构造函数有一个必须遵守的规则,即构造函数不能定义为虚函数。但有一个具体的应用是要求是在不同的场景下通过一个指针或者引用生成不同的对象,这就类似于类型的动态生成,即在执行期才能确定具体的对象。这怎么实现呢?
下面我们介绍两种方法:
1、不管是在effective c++ 还是在设计模式中,提到的一种特别的替代继承的方法,即组合。采用组合的方法来实现构造函数虚化的功能。具体实现方式为:
class base { //抽象基类,其中至少含有一个纯虚函数,但其构造函数非虚 public: .... }; class derive1:public base { public: .... }; class derive1:public base { //没有内含任何纯虚函数 public: .... }; class derive2:public base { //没有内含任何纯虚函数 public: .... }; class object { public: ... private: list<base*> components; }; |
在上面的代码中,class object含有一个list对象用来装载base类对象,但是由于base类是一个抽象类,所以list中得内容实际为derive1或者为derive2对象,实现了动态产生对象。
在object类的实现函数还有注意下面的代码:
object:object(base* b) { if(b) { components.push_back(b);//将具体的base的子类对象加到components list尾端 } } |
2、还有一种方法是利用“虚函数的返回类型”规则中得一个宽松点,那是c++标准比较晚才被接纳的一个规则。当derived class重新定义其base class的一个虚函数时,不再需要一定得声明与原本相同的返回类型。如果函数的分返回类型是个指针或者引用,并指向一个base class,那么derived class的函数可以返回一个指针或引用指向该base class的derived class。这不会造成c++的类型错误,却准确的声明出像virtual copy constructors这样的函数。
class base { public: //声明virtual copy constructor virtual base *clone() const=0; .... }; class derive1:public base { //声明virtual copy constructor virtual derive1 *clone() const { return new derive1(*this); } .... }; class derive2:public base { //声明virtual copy constructor virtual derive2 *clone() const { return new derive2(*this); } .... }; class object { public: object(const base& rhs); ... private: list<base*> components; }; |
object类的实现方法有:
object:object(const base& rhs) { for(list<base*>::const_iterator it=rhs.components.begin();it!=rhs.components.end();it++) { components.push_back((*it)->clone());//将具体的base的子类对象加到components list尾端 } } |
注意,上面的两种方法并不是真正的将构造函数直接定义为虚函数,而是采用其他的方法将构造函数产生虚化的效果。