在上一篇文章中介绍了实现"virtual构造函数"的方法--《C++构造与析构(16) - virtual构造函数》。
有没有可能在不知道类的具体类型的情况下创建一个对象?
众所周知,拷贝构造函数是用一个已经存在的对象,来构造一个新的对象。新对象的初始状态取决于已存在对象的状态。当使用一个对象初始化另一个对象时,编译器会调用拷贝构造函数。但是,编译器需要知道确切的类型信息才能调用拷贝构造函数。
#include <iostream>
using namespace std;
class Base {
public:
};
class Derived : public Base {
public:
Derived() { cout << "Derived created" << endl; }
Derived(const Derived& rhs) { cout << "Derived created by deep copy" << endl; }
~Derived() { cout << "Derived destroyed" << endl; }
};
int main() {
Derived s1;
Derived s2 = s1; // 编译器会调用拷贝构造函数
// s1和s2的类型对于编译器是具体的/确切知道的。
// 基于基类指针或引用(指向的是子类对象),如何创建Derived1或Derived2对象?
return 0;
}
运行结果:
Derived created
Derived created by deep copy
Derived destroyed
Derived destroyed
如果用户无法确定对象的类型,此时如何使用拷贝构造函数?例如virtual构造函数在运行时期间创建了一个对象。当使用拷贝构造函数创建对象时,如果已存在对象是virtual构造函数创建的,我们无法使用拷贝构造函数。需要自定义一个在运行时可以拷贝对象的函数。
举例说明:有一个绘图程序,它支持从已有的图案进行拷贝-粘贴。
从程序员的角度看,我们无法知道哪个图案会被拷贝-粘贴,因为它是一个运行时的行为。在这种情况下,就需要使用virtual拷贝构造函数来帮助。
类似地,对于一个记录板程序,从已存在对象拷贝,然后粘贴。具体对象类型是运行时的行为,无法提前知道。就需要使用virtual拷贝构造函数了。
参见下面例子:
#include <iostream>
using namespace std;
class Base {
public:
Base() {}
virtual ~Base() {} // 确保调用子类析构函数
virtual void ChangeAttributes() = 0;
static Base* Create(int id); // 做为"virtual constructor"
virtual Base* Clone() = 0; // 做为"virtual copy constructor"
};
class Derived1 : public Base {
public:
Derived1() { cout << "Derived1 created" << endl; }
Derived1(const Derived1& rhs) { cout << "Derived1 created by deep copy" << endl; }
~Derived1() { cout << "~Derived1 destroyed" << endl; }
void ChangeAttributes() { cout << "Derived1 Attributes Changed" << endl; }
Base* Clone() { return new Derived1(*this); }
};
class Derived2 : public Base {
public:
Derived2() { cout << "Derived2 created" << endl; }
Derived2(const Derived2& rhs) { cout << "Derived2 created by deep copy" << endl; }
~Derived2() { cout << "~Derived2 destroyed" << endl; }
void ChangeAttributes() {cout << "Derived2 Attributes Changed" << endl; }
Base* Clone() { return new Derived2(*this); }
};
class Derived3 : public Base {
public:
Derived3() { cout << "Derived3 created" << endl; }
Derived3(const Derived3& rhs) { cout << "Derived3 created by deep copy" << endl; }
~Derived3() { cout << "~Derived3 destroyed" << endl; }
void ChangeAttributes() { cout << "Derived3 Attributes Changed" << endl; }
Base* Clone() { return new Derived3(*this); }
};
Base* Base::Create(int id) {
//如果新的Derived类加入,只需要在此添加if-else.
//User类不需要重新编译即可支持新加的对象。
if (id == 1) { return new Derived1; }
else if (id == 2) { return new Derived2; }
else { return new Derived3; }
}
class User {
public:
// 运行时期间创建Base对象
User() : pBase(0) {
int input;
cout << "Enter ID (1, 2 or 3): ";
cin >> input;
while ((input != 1) && (input != 2) && (input != 3)) {
cout << "Enter ID (1, 2 or 3 only): ";
cin >> input;
}
// 调用"Virtual Constructor"来创建对象
pBase = Base::Create(input);
}
~User() {
if (pBase) {
delete pBase;
pBase = 0;
}
}
void Action() {
// 赋值当前对象
Base* pNewBase = pBase->Clone();
pNewBase->ChangeAttributes();
delete pNewBase;
}
private:
Base* pBase;
};
int main() {
User* user = new User();
user->Action();
delete user;
}
运行结果:
Enter ID (1, 2 or 3): 3
Derived3 created
Derived3 created by deep copy
Derived3 Attributes Changed
~Derived3 destroyed
~Derived3 destroyed
User类使用virtual constructor创建一个对象。这个对象取决于用户输入值input ID。
函数Action()会拷贝已存在对象给新对象,并修改新对象的属性。使用虚函数Clone()来创建新对象的过程,即被称为virtual copy constructor。
这里使用Clone()方法的这种概念,就属于设计模式中的 原型模式prototype pattern。具体可参考本人的这篇文章 《设计模式(4) - Prototype原型模式》。