虚拟函数是面向对象编程中的一种关键机制,它允许在基类和派生类之间实现多态性。这意味着我们可以在基类中定义一个函数,然后在派生类中对其进行重写,以提供特定于该派生类的实现。
1. 虚拟函数的基本概念
使用virtual
关键字声明的函数称为虚拟函数。虚拟函数的特点在于它的行为会在运行时动态地根据对象的实际类型进行确定,而不是在编译时。
值得注意的是,虚拟函数必须在基类中有一个可执行的主体,其语义与普通函数相同。但是,派生类可以选择重写这个函数。
2. 如何工作?
当我们通过基类的指针调用一个虚拟函数时,它会根据该指针实际指向的对象类型来确定应该调用哪个函数。如果派生类没有重写这个虚拟函数,则会默认调用基类的实现。
例如,考虑一个名为CTetrisShape
的基类,该类定义了一个虚拟函数Draw
。该函数在基类中没有特定的实现,但在派生类,如CTetrisShape1
和CTetrisShape6
中有特定的实现。这意味着当我们调用Draw
函数时,它的行为会根据我们操作的是哪个类的对象来确定。
3. 示例解析
- 基类的定义:
CTetrisShape
是一个基类,包含了许多属性,如m_xpos
和m_ypos
等,代表形状在游戏中的位置。此外,它还定义了一个虚拟函数Draw
和其他函数。 - 派生类的定义:
CTetrisShape1
和CTetrisShape6
是从CTetrisShape
派生的类,它们都提供了Draw
函数的特定实现,用于绘制特定形状。 对于CTetrisShape1
,当m_turn
为0或2时,形状是水平的;否则,形状是垂直的。 而对于CTetrisShape6
,它描述的形状是一个方形,并有其特定的绘图方式。 - 创建和绘制形状:
在函数CTetrisField::NewShape
中,首先随机选择一个形状,然后创建相应的形状对象,并调用其Draw
函数进行绘制。
4. 注意事项
- 虚拟函数应该避免在构造函数和析构函数中被调用,因为在这种情况下其结果是未定义的。
- 虽然析构函数总是虚拟的,但最好还是使用
virtual
关键字显式地声明它。
总结
虚拟函数为实现面向对象的多态性提供了强大的工具,使得我们可以编写更加灵活和通用的代码。当我们不确定在运行时需要哪种特定行为时,或当我们想要为已有的代码提供新的实现时,这一特性尤其有用。