在本指南中,我们将看到什么是虚函数以及我们使用它们的原因。当我们在一个类中将一个函数声明为虚函数时,所有覆盖此函数的子类默认情况下的函数实现为虚函数(无论它们是否标记为虚拟)。
为什么我们声明一个虚函数?
让编译器知道需要在运行时解析对此函数的调用(也称为晚期绑定和动态链接),以便确定对象类型并且调用函数的正确版本。
让我们举个例子来理解当我们不将覆盖函数标记为虚拟时会发生什么。
示例 1:覆盖非虚函数
在这里看到问题。即使我们指向子类的实例(对象)的父类指针,也会调用该函数的父类版本。
您可能在想我为什么创建指针,我可以简单地创建子类的对象,如下所示:Dog obj;
并将Dog
实例分配给它。好吧,在这个例子中我只有一个子类,但是当我们有一个包含多个子类的大项目时,不建议单独创建子类的对象,因为它增加了复杂性并且代码容易出错。在此示例之后更加清晰。
#include<iostream>
using namespace std;
//Parent class or super class or base class
class Animal{
public:
void animalSound(){
cout<<"This is a generic Function";
}
};
//child class or sub class or derived class
class Dog : public Animal{
public:
void animalSound(){
cout<<"Woof";
}
};
int main(){
Animal *obj;
obj = new Dog();
obj->animalSound();
return 0;
}
输出:
This is a generic Function
示例 2:使用虚函数
在这种情况下,输出是Woof
,这是我们所期望的。在这种情况下会发生什么?由于我们将函数animalSound()
标记为虚拟,因此在运行时解析对函数的调用,编译器在运行时确定对象的类型并调用适当的函数。
#include<iostream>
using namespace std;
//Parent class or super class or base class
class Animal{
public:
virtual void animalSound(){
cout<<"This is a generic Function";
}
};
//child class or sub class or derived class
class Dog : public Animal{
public:
void animalSound(){
cout<<"Woof";
}
};
int main(){
Animal *obj;
obj = new Dog();
obj->animalSound();
return 0;
}
输出:
Woof