使用virtual:如果方法是通过引用类型或指针而不是对象调用的,它将确定使用哪一种方法。如果没有使用关键字irtual,程序将根据引用类型或指针类型选择方法;如果使用了irtual,程序将根据引用或指针指向的对象的类型来选择方法。对于一个函数ViewAcct()来说,如果ViewAcct()不是虚的,则程序的行为如下:
// behavior with non-virtual ViewAcct()
// method chosen according to reference type
Brass dom("Dominic Banker", 11224, 4183.45);
BrassPlus dot("Dorothy Banker", 12118, 2592.00);
Brass & b1_ref = dom;
Brass & b2_ref = dot;
b1_ref.ViewAcct(); // use Brass::ViewAcct()
b2_ref.ViewAcct(); // use Brass::ViewAcct()
引用变量的类型为Brass,所以选择了Brass::ViewAccount()。
使用Brass指针代替引用时,行为将与此类似。
如果ViewAcct()是虚的,则行为如下:
// behavior with virtual ViewAcct()
// method chosen according to object
Brass dom("Dominic Banker", 11224, 4183.45);
BrassPlus dot("Dorothy Banker", 12118, 2592.00);
Brass & b1_ref = dom;
Brass & b2_ref = dot;
b1_ref.ViewAcct(); // use Brass::ViewAcct()
b2_ref.ViewAcct(); // use BrassPlus::ViewAcct()
这里两个引用的类型都是Brass,但b2_ref引用的是一个BrassPlus对象,所以使用的是BrassPlus::ViewAcct()。使用Brass指针代替引用时,行为将类似。
虚析构函数:基类声明了一个虚析构函数。这样做是为了确保释放派生对象时,按正确的顺序调用析构函数。
3.演示虚方法的行为
假设要同时管理Brass和BrassPlus账户,如果能使用同一个数组来保存Brass和BrassPlus对象,将很有帮助,但这时不可能的。数组中所有元素的类型必须相同,而Brass和BrassPlus是不同的类型。然而,可以创建指向Brass的指针数组。这样,每个元素的类型都相同,但由于使用的是公有继承模型,因此Brass指针既可以指向Brass对象,也可以指向BrassPlus对象。因此,可以使用一个数组来表示多种类型的对象。这就是多态性。
4.为何需要虚析构函数
在程序清单13.10中,使用delete释放由new分配的对象的代码说明了为何基类应包含一个虚析构函数,虽然有时好像并不需要析构函数。如果析构函数不是虚的,则将纸雕用对应与指针类型的析构函数。对于程序清单13.10,这意味着只有Brass的析构函数被调用,即使指针指向的是一个BrassPlus对象。如果析构函数是虚的,将调用相应对象类型的析构函数。因此,如果指针指向的是BrassPlus对象,将调用BrassPlus的析构函数,然后自动调用基类的析构函数。因此,使用虚析构函数可以确保正确的析构函数序列被调用!