1 构造函数的虚化
1 构造虚函数
构造函数与类的名称相同,因此,此处所指的虚化,并非让构造函数变成虚函数,而是让其具有类似虚函数的行为:
当条件不同时,不同的对象会被创建出来。
下面的代码展示了“虚构造函数”的应用。
class Base {
}
class Derive1 : public Base {
}
class Derive2: public Base {
}
Base* constructObject(std::istream& inStream) {
Base* obj;
if (/*condition0*/) {
// create Base's object
} else if (/*condition1*/) {
// create Derive1's object;
} else {
// create Derive2's object
}
return obj;
}
2 “虚复制构造函数”
如下代码所示。C++11中,虚函数允许返回类型不同,因此,Base, Derive1, Derive2三个类型的clone可以看作时override。这样,每次调用clone函数,可以根据相应的对象,来进行复制。
class Base {
public:
virtual Base* clone() const;
}
class Derive1 : public Base {
public:
virtual Derive1* clone() const;
}
class Derive2 : public Base {
public:
virtual Derive2* clone() const;
}
void func()
{
std::vector<Base*> objList, targetList;
for (int idx = 0; idx < objList.size(); ++idx) {
targetList.push_back(objList->clone()); // 关键代码
}
}
clone()通常直接调用函数的“复制构造函数”。代码如下:
Base* Base::clone()
{
return new Base(*this);
}
Derive1* Derive1::clone()
{
return new Derive1(*this);
}
...
总结:通过增加一层虚函数clone,我们实现了,根据不同类型来进行复制构造的操作,从而实现多态。
2 非成员函数地虚化
流操作“<<”用于输出内存中的内容。现在,我希望,操作符“<<”能根据不同类型来输出内容。下面将讨论两种情况。
1 类型之间没有关系
比如,我手头有3个类,定义如下。他们之间没有任何关系,那么就需要针对这三个类型,重载"<<"。这样,就可以实现虚化——针对不同类型,能都在运行期间动态调整。
class My1 {
}
class My2 {
}
class My3 {
}
std::ostream operator << (std::ostream& out, const My1& obj);
std::ostream operator << (std::ostream& out, const My2& obj);
std::ostream operator << (std::ostream& out, const My3& obj);
实际上,这与虚函数的定义有一定差别。虚函数需要限定如下几个条件。因此,我们引出第二种情况。
1 “虚”行为,针对的是有继承关系的类。
2 表面上看是基类的行为,实际上可能是子类的行为。
3 基类和子类的行为不完全相同。
2 非成员函数的虚行为
现在有若干水果类,继承与定义关系如下。那么,我们需要根据不同的水果类型,来输出其名字。那么就可以利用虚函数。
class Fruit {
pulic:
virtual std::string print();
}
class Apple : public Fruit {
public:
virtual std::string print();
}
class BananaApple : public Apple {
public:
virtual std::string print();
}
std::ostream operator << (std::ostream& out, const Fruit& obj)
{
obj.print(); // 根据多态,上面定义的三个类中的print都可以被调用
}
上面重载的<<,展示了我们可以传入基类,然后利用基类的多态性,从而实现非成员函数的多态性。