C++虚函数原理

目录

虚函数表的布局

无继承关系的虚函数

存在继承关系的虚函数

单继承:子类不覆盖基类虚函数的情况

单继承:子类覆盖了基类的一个虚函数的情况

单继承:定义了基类没有的虚函数

多继承:存在虚函数覆盖同时又存在自身定义的虚函数的类对象布局

多继承:如果有三个基类: 虚函数表分别是有, 没有, 有

父子对象指针间的转换与函数调用


虚函数表的布局

无继承关系的虚函数

如果一个类中声明了一个虚函数,那么编译器就会为这个类在所有变量的前面增加了一个void **的指针变量__vfptr(注意不是数组),我们称__vfptr指向的void*数组为虚函数表

这个类每添加一个虚函数,void **变量__vfptr里就会增加一个void*的指针

同一个类的不同实例都有一个__vfptr指针,指向同一个虚函数表

C++虚函数原理

虚函数表保存在哪里? 

  1. 它是编译器在编译时期为我们创建好的, 只存在一份
  2. 定义类对象时, 编译器自动将类对象的__vfptr指向这个虚函数表

 

存在继承关系的虚函数

单继承:子类不覆盖基类虚函数的情况

class Base1
{
public:
    int base1_1;
    int base1_2;

    virtual void base1_fun1() {}
    virtual void base1_fun2() {}
};

class Derive1 : public Base1
{
public:
    int derive1_1;
    int derive1_2;
};

C++虚函数原理

单继承:子类覆盖了基类的一个虚函数的情况

class Base1
{
public:
    int base1_1;
    int base1_2;

    virtual void base1_fun1() {}
    virtual void base1_fun2() {}
};

class Derive1 : public Base1
{
public:
    int derive1_1;
    int derive1_2;

    // 覆盖基类函数
    virtual void base1_fun1() {}
};

C++虚函数原理

无论是通过Derive1的指针还是Base1的指针来调用此函数, 调用的都将是被继承类重写后的那个函数

单继承:定义了基类没有的虚函数

class Base1
{
public:
    int base1_1;
    int base1_2;

    virtual void base1_fun1() {}
    virtual void base1_fun2() {}
};

class Derive1 : public Base1
{
public:
    int derive1_1;
    int derive1_2;

    virtual void derive1_fun1() {}
};
  1.  继承类Derive1的虚函数表被加在基类的后面
  2. 由于Base1只知道自己的两个虚函数索引[0][1], 所以就算在后面加上了[2], Base1根本不知情, 不会对它造成任何影响

C++虚函数原理

多继承:存在虚函数覆盖同时又存在自身定义的虚函数的类对象布局

class Base1
{
public:
    int base1_1;
    int base1_2;

    virtual void base1_fun1() {}
    virtual void base1_fun2() {}
};

class Base2
{
public:
    int base2_1;
    int base2_2;

    virtual void base2_fun1() {}
    virtual void base2_fun2() {}
};

// 多继承
class Derive1 : public Base1, public Base2
{
public:
    int derive1_1;
    int derive1_2;

    // 基类虚函数覆盖
    virtual void base1_fun1() {}
    virtual void base2_fun2() {}

    // 自身定义的虚函数
    virtual void derive1_fun1() {}
    virtual void derive1_fun2() {}
};

Derive1的虚函数表依然是保存到第1个拥有虚函数表的那个基类的后面的

C++虚函数原理

如果第1个直接基类没有虚函数(表)

class Base1
{
public:
    int base1_1;
    int base1_2;
};

class Base2
{
public:
    int base2_1;
    int base2_2;

    virtual void base2_fun1() {}
    virtual void base2_fun2() {}
};

// 多继承
class Derive1 : public Base1, public Base2
{
public:
    int derive1_1;
    int derive1_2;

    // 自身定义的虚函数
    virtual void derive1_fun1() {}
    virtual void derive1_fun2() {}
};

那么哪个基类有虚函数表,哪个类就会被放到前面,Derive1的虚函数表仍然保存到最前面哪个拥有虚函数表的那个基类的后面

C++虚函数原理

 如果两个基类都没有虚函数表

class Base1
{
public:
    int base1_1;
    int base1_2;
};

class Base2
{
public:
    int base2_1;
    int base2_2;
};

// 多继承
class Derive1 : public Base1, public Base2
{
public:
    int derive1_1;
    int derive1_2;

    // 自身定义的虚函数
    virtual void derive1_fun1() {}
    virtual void derive1_fun2() {}
};

C++虚函数原理

多继承:如果有三个基类: 虚函数表分别是有, 没有, 有

那么有虚虚函数表的都会被提到前面

C++虚函数原理

 

父子对象指针间的转换与函数调用

如果把一个子类指针转为父类指针,那么调用函数会按一下规则调用

  1. 如果不是虚函数, 直接调用指针对应的基本类的那个函数
  2. 如果是虚函数, 则查找虚函数表, 并进行后续的调用. 虚函数表在定义一个时, 编译器就为我们创建好了的. 所有的, 同一个类, 共用同一份虚函数表

 

以上全部整理总结自:https://blog.twofei.com/496/(感谢,无敌详细版请参照它)