C++ 虚函数

2025 年 5 月 1 日 | 阅读 8 分钟

在 C++ 中,**虚函数**是可由派生类重写的成员函数。它在基类中声明,并在派生类中重新定义。使用 virtual 关键字可以定义虚函数。

当我们在基类中声明函数时,我们可以使用指针引用来调用虚类并在派生类中运行其虚函数。它也称为虚方法。

虚函数用于通知编译器对函数执行后期绑定或动态链接。它支持运行时多态性,允许使用虚表 (vtable) 和虚指针 (vptr) 动态解析函数调用。

语法

它具有以下语法:

在此语法中,baseClass_name 表示基类的名称,funct_name 表示给定函数的名称。

C++ 虚函数示例

让我们通过一个实例来演示 C++ 中的虚函数。

示例

编译并运行

输出

It is the print derived class method
It is the show base class method

说明

在此示例中,我们创建了一个包含虚函数 print() 的基类 baseClass,它还包含一个非虚函数 show()。在 main() 函数中,基类指针 (bptr) 设置为指向派生类 (d1) 的对象。当执行 bptr->display() 时,将发生后期绑定,这意味着调用的函数是派生类中的重写函数。

虚函数规则

C++ 中虚函数的几个规则如下:

  • 虚函数必须是某个类的成员。
  • 虚函数不能是静态成员。它们可以通过对象指针访问。
  • 在基类中,虚函数可以具有任何访问级别(包括 public、private 和 protected)。
  • 虚函数可以是另一个类的友元。
  • 它们可以具有任何返回类型、数量和参数类型。
  • 虚函数应在基类中定义,即使它未在程序中使用。
  • 基类和所有派生类的虚函数原型应相同。如果两个函数具有相同的名称但不同的原型,C++ 将把它们视为重载函数。
  • 我们不能有虚构造函数,但可以有虚析构函数。

虚表 (vTable) 和虚指针 (vPtr)

在 C++ 中,虚表 (vTable) 是一个隐藏过程,主要用于使用虚函数实现运行时多态性。在虚函数中,每个类都有一个 vTable。该类的每个对象都有一个指向 vTable 的隐藏 vPtr。vTable 包含可对该类对象调用的虚函数的地址。

另一方面,虚指针是具有虚函数的类的每个对象中的隐藏指针。编译器将其作为成员函数包含在内。它用于指向该类的 vTable。当程序中调用虚函数时,VPTR 有助于在运行时在 VTable 中找到正确的函数地址。

C++ vTable 和 vPtr 示例

让我们通过一个示例来演示 C++ 中的 vTable 和 vPtr。

示例

编译并运行

输出

RacingCar is starting with a loud roar!

说明

在此示例中,我们创建了一个基类 Car,它定义了一个虚函数 start(),该函数在派生类 RacingCar 中重写。在 main() 函数中,基类指针 carPtr 指向一个 RacingCar 对象。

当调用 carPtr->start() 时,使用 vTable 和 vPtr 发生后期绑定,导致在运行时执行 RacingCar 版本的 start()。

C++ 中的后期绑定/动态绑定

在 C++ 中,后期绑定是一种在运行时解析函数调用的机制。它仅在通过指向基类的指针或引用调用虚函数时发生。因此,编译器在运行时确定对象的类型,然后绑定函数调用。

当通过指向基类的指针或引用对对象调用虚函数时,我们可以使用在运行时与实际对象连接的虚函数表 (vtable)。它允许我们执行正确的派生类。

C++ 后期绑定示例

让我们通过一个示例来演示 C++ 中的后期绑定。

示例

编译并运行

输出

Dog color gray

说明

在此示例中,我们创建了一个基类 Animal,它定义了一个虚函数 display()。之后,派生类 Dog 重写了虚函数。ptr ->display() 函数调用后期绑定,并实现 Dog 类的 display() 函数,因为类型 dog() 是一个实际对象。

C++ 纯虚函数

在 C++ 中,纯虚函数是没有实现的抽象方法。纯虚函数也称为“空操作”函数。它是在基类中声明的函数,相对于基类没有函数定义。

包含纯虚函数的类不能直接用于创建对象。这些类型的类称为抽象基类。基类的主要目的是向派生类提供特性,并创建用于实现运行时多态性的基指针。

语法

它具有以下语法:

C++ 纯虚函数示例

让我们通过一个示例来演示 C++ 中的纯虚函数。

示例

编译并运行

输出

Derived class is derived from the base class.

说明

在此示例中,基类包含纯虚函数。因此,基类是一个抽象基类。我们无法创建基类的对象。

C++ 中虚函数的优缺点

C++ 中虚函数的几个优缺点如下:

虚函数的优点

  • 它支持派生类中的派生函数,从而允许方法重写。
  • 它允许设计用户友好的应用程序,对引入新的派生类限制最小,即现有基类代码无需修改。
  • 它提高了程序执行的灵活性,因为函数调用是在程序执行期间完成的,而不是在编写代码期间完成的。
  • 当派生类存储在基类指针中以处理虚函数情况时,它可确保派生类的全部功能。
  • 它在 GUI 框架、游戏引擎和基于插件的架构中很有用。

虚函数的缺点

  • 由于虚机制,函数调用需要很长时间,这使得编译器难以优化,因为它不知道将调用哪个函数。
  • 在复杂的系统中,虚函数会使查找函数被调用的位置变得更加困难。
  • 虚函数可能会导致某些优化技术出现问题,从而降低性能。
  • 在虚函数中,每个类都包含一个虚表 (vtable),这会增加其主内存。

C++ 虚函数 MCQ

1) 在 C++ 中,以下哪个类用于重新定义虚函数?

  1. 父类
  2. 基类
  3. 派生类
  4. 以上全部。

答案: c) 派生类


2) 在 C++ 后期/动态绑定中,函数调用在何时解析?

  1. 编译时
  2. 运行时
  3. 无限时间
  4. 以上都不是

答案: b) 运行时


3) 以下程序的输出是什么?

  1. 这是一辆跑车。
  2. 这是一辆车
  3. 运行时错误
  4. 语法错误

答案: a) 这是一辆跑车


4) 在 C++ 中,以下哪个选项用于访问虚函数?

  1. Array
  2. 变量
  3. 对象指针
  4. Object

答案: c) 对象指针


5) C++ 中纯虚函数的正确语法是什么?

  1. pure virtual return_type func();
  2. virtual return_type func() = 0;
  3. virtual return_type func();
  4. virtual return_type func() pure;

答案: b) virtual return_type func() = 0;


下一主题C++ 接口