虚函数是基类中的一个函数,它在派生类中被重载,它告诉编译器对该函数执行后期绑定。
Virtual
关键字用于修饰基类的虚函数。
在后期绑定中,函数调用在运行时发生,因此,编译器在运行时确定对象的类型,然后再绑定函数调用,后期绑定也称为动态绑定或运行时绑定。
让我们来看一下virtual
关键字的作用是什么
class Base
{
public:
void show()
{
cout << "基类";
}
};
class Derived:public Base
{
public:
void show()
{
cout << "派生类";
}
}
int main()
{
Base* b; //基类指针
Derived d; //派生类对象
b = &d;
b->show(); //早期绑定
}
以上实例输出结果:
基类
当我们使用基类的指针来指向派生类的对象时,基类指针或引用总是会调用基类的函数。
我们可以在声明基类的函数时使用 virtual 关键字将它们设为虚函数,虚拟关键字将会使该函数后期绑定。
class Base
{
public:
virtual void show()
{
cout << "基类\n";
}
};
class Derived:public Base
{
public:
void show()
{
cout << "派生类";
}
}
int main()
{
Base* b; //基类指针
Derived d; //派生类对象
b = &d;
b->show(); //后期绑定
}
以上实例输出结果:
派生类
在基类的函数中使用 Virtual 关键字时,会发生后期绑定,并且将调用函数的派生版本,因为基类指针指向派生类对象。
我们可以借助virtual关键字用基类指针调用派生类的private函数,编译器仅在编译时检查访问说明符,因此,在运行时发生后期绑定时,它不会检查我们是在调用private函数还是public函数。
#include <iostream>
using namespace std;
class A
{
public:
virtual void show()
{
cout << "基类\n";
}
};
class B: public A
{
private:
virtual void show()
{
cout << "派生类\n";
}
};
int main()
{
A *a;
B b;
a = &b;
a->show();
}
以上实例输出结果:
派生类
为了完成后期绑定,编译器为每个具有虚函数的类创建 虚函数表,虚函数的地址被插入到这些表中,每当创建此类的对象时,编译器都会插入一个名为 vpointer 的虚指针,指向该对象的虚函数表。因此,当调用函数时,编译器能够通过使用虚指针绑定正确的函数来解决调用。