虚函数是在基类中声明并由派生类重新定义(覆盖)的成员函数。当您使用指针或对基类的引用来引用派生类对象时,您可以为该对象调用虚函数并执行派生类的函数版本。
虚函数确保为对象调用正确的函数,而不管用于函数调用的引用(或指针)的类型。它们主要用于实现运行时多态性函数在基类中使用virtual关键字声明。函数调用的解析是在运行时完成的。
虚拟功能规则
虚函数不能是静态的。虚函数可以是另一个类的友元函数。应该使用基类类型的指针或引用来访问虚函数,以实现运行时多态性。虚函数的原型在基类和派生类中应该是相同的。它们总是在基类中定义并在派生类中被覆盖。派生类不需要重写(或重新定义虚函数),在这种情况下,使用函数的基类版本。一个类可以有虚拟析构函数,但不能有虚拟构造函数。Virtual Functions 的编译时(早期绑定)VS 运行时(后期绑定)行为
考虑以下显示虚函数运行时行为的简单程序。
// CPP program to illustrate// concept of Virtual Functions#include
输出:
打印派生类显示基类
**说明:**运行时多态性只能通过基类类型的指针(或引用)来实现。此外,基类指针既可以指向基类的对象,也可以指向派生类的对象。在上面的代码中,基类指针“bptr”包含派生类的对象“d”的地址。
后期绑定(运行时)根据指针的内容(即指针指向的位置)进行,早期绑定(编译时)根据指针的类型进行,因为 print() 函数是用 virtual 关键字声明的,所以它将在运行时绑定(输出是打印派生类,因为指针指向派生类的对象)并且 show() 是非虚拟的,因此它将在编译时绑定(输出是显示基类因为指针是基本类型)。
**注意:**如果我们在基类中创建了一个虚函数,并且它在派生类中被覆盖,那么我们不需要在派生类中使用 virtual 关键字,函数在派生类中被自动视为虚函数。
虚函数的工作(VTABLE 和 VPTR 的概念)正如这里
所讨论的,如果一个类包含一个虚函数,那么编译器本身会做两件事。
考虑下面的例子:
// CPP program to illustrate// working of Virtual Functions#include
输出:
基数 1派生 2基数 3基数 4
**说明:**最初,我们创建一个基类类型的指针,并用派生类对象的地址对其进行初始化。当我们创建派生类的对象时,编译器会创建一个指针作为类的数据成员,其中包含派生类的 VTABLE 的地址。
与上面的示例一样,使用了类似的后期和早期绑定概念。对于 fun_1() 函数调用,函数的基类版本被调用, fun_2() 在派生类中被覆盖,因此派生类版本被调用, fun_3() 在派生类中未被覆盖并且是虚函数,因此被调用基类版本,同样 fun_4() 没有被覆盖,所以基类版本被调用。
**注意:**派生类中的 fun_4(int) 与基类中的虚函数 fun_4() 不同,因为这两个函数的原型不同。