9.6.3 使用引用处理虚函数
如果我们定义一个形参为基类引用的函数,则可以给该函数传递派生类的对象作为实参。该函数在执行的时候,将自动为传递进来的对象选择适当的虚函数。我们将上一个示例中的main()函数修改成调用一个形参为引用的函数,就可以看到这种情况发生。
试一试:使用引用处理虚函数
让我们把对ShowVolume()的调用移到某个独立的函数中,然后从main()中调用这个独立的函数:
- // Ex9_09.cpp
- // Using a reference to call a virtual function
- #include <iostream>
- #include "GlassBox.h" // For CBox and CGlassBox
- using std::cout;
- using std::endl;
-
- void Output(const CBox& aBox); // Prototype of function
-
- int main()
- {
- CBox myBox(2.0, 3.0, 4.0); // Declare a base box
- CGlassBox myGlassBox(2.0, 3.0, 4.0);
// Declare derived box of same size -
- Output(myBox); // Output volume of base class object
- Output(myGlassBox); // Output volume of derived class object
-
- cout << endl;
- return 0;
- }
-
- void Output(const CBox& aBox)
- {
- aBox.ShowVolume();
- }
该示例的Box.h和GlassBox.h文件与上一个示例的同名文件的内容相同。
示例说明
main()函数现在基本上由两次对Output()函数的调用组成,第一次用基类对象作为实参,第二次用派生类对象作为实参。因为形参是基类的引用,所以Output()函数可以接受这两种类对象实参,并根据初始化引用的对象种类,调用适当的虚函数Volume()。
该程序产生的输出与上一个示例完全相同,从而证实虚函数机制确实能够借助于引用形参起作用。
不完整的类定义
在上一个示例的开头部分,我们添加了Output()函数的原型声明。为了处理这条声明,编译器需要知道CBox类的定义,因为形参属于CBox&类型。在当时的情况下,CBox类的定义在这条声明语句的位置是可用的,因为前面有嵌入GlassBox.h头文件的#include指令,而GlassBox.h又有嵌入Box.h的#include指令。
但是,有些情况下我们虽然需要这样的函数声明,但类定义却不能以上述方式嵌入,此时我们就需要某种其他方法来至少将名称CBox标识为类类型。如果是这种情况,我们可以在Output()函数的原型前面提供CBox类的不完整定义。提供CBox类不完整定义的语句很简单:
class CBox;
该语句只是将名称CBox标识为此刻还没有被定义的类,但已经足以使编译器知道CBox是个类名,同时使编译器能够处理Output()函数的原型。如果不指出CBox是一个类,那么Output()的原型声明将导致编译器生成一条出错消息。