C++ 虚函数



C++ 中的虚函数

虚函数是基类中的一个函数,它在派生类中被重载,它告诉编译器对该函数执行后期绑定

Virtual 关键字用于修饰基类的虚函数。



C++ 中的后期绑定

在后期绑定中,函数调用在运行时发生,因此,编译器在运行时确定对象的类型,然后再绑定函数调用,后期绑定也称为动态绑定运行时绑定

没有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();     //早期绑定
}

以上实例输出结果:

基类

当我们使用基类的指针来指向派生类的对象时,基类指针或引用总是会调用基类的函数。



在 C++ 中使用Virtual关键字

我们可以在声明基类的函数时使用 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关键字访问派生类的私有方法

我们可以借助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(); 
}

以上实例输出结果:

派生类


C++ 中后期绑定的机制

C++ 中后期绑定的机制

为了完成后期绑定,编译器为每个具有虚函数的类创建 虚函数表,虚函数的地址被插入到这些表中,每当创建此类的对象时,编译器都会插入一个名为 vpointer 的虚指针,指向该对象的虚函数表。因此,当调用函数时,编译器能够通过使用虚指针绑定正确的函数来解决调用。



要记住的重点

  1. 只有基类函数的声明需要Virtual关键字,可以只声明而不定义。
  2. 如果一个函数在基类中被声明为virtual,那么它在它的所有派生类中都是虚函数。
  3. 虚函数的地址放在虚函数表中,编译器使用虚指针指向虚函数。