C++运行时通过基类指针或引用调用派生类虛函数的实现原理: 虛函数表

我们知道要实现运行时的多态, 必须在基类中声明和定义相关的虛函数, 并在派生类中重新实现基类中的虛函数.
当编译器见到这种继承层次结构的时候, 编译器将为定义了虛函数的基类和覆盖了基类虛函数的派生类分别创建一张虛函数表(Virtual Function Table, VFT), 也就是说通过编译器的编译, 基类和派生类的代码中都将有自己的虛函数表.
为这些类创建实例化对象时, 会在实例化的对象中插入一个指向对应的虛函数表的指针 (VFT*), 该指针通常在存放在对象的开头区域.
而虛函数表(VFT)可以看做就是一个其数据类型为函数指针的静态数组, 每一个函数指针指向对应类中的一个虛函数.

例如:
基类:

class Base
{
public:
    virtual void Func1()
    {
    // Func1 implementation
    }
    virtual void Func2()
    {
    // Func2 implementation
    }// .. so on and so forth
    virtual void FuncN()
    {
    // FuncN implementation
    }
};

派生类:

class Derived: public Base
{
public:
    virtual void Func1()
    {
    // Func2 overrides Base::Func2()
    }
    // no implementation for Func2()
    virtual void FuncN()
    {
    // FuncN implementation
    }
};

类Base和Derived的虛函数表

Derived objDerived;
objDerived.Func2();

上述代码中编译器将查找objDerived对象所属的Derived类的VFT, 确保能够调用Base::Func2()函数.

void DoSomething(Base& objBase)
{
    objBase.Func1();
    // invoke Derived::Func1
    }
    int main()
    {
    Derived objDerived;
    DoSomething(objDerived);
};

在上述代码中, 虽然将派生类的对象objDerived通过引用传递给了objBase, 进而被解读为一个Base类的实例, 但是该实例的VFT*依然指向Derived类的虛函数表, 因此通过基类引用调用Func1()函数时, 实际上被调用的是派生类的虛函数Derived::Func1(). 注意必须是基类的指针或引用来调用基类虛函数, 而不能是直接传值, 因为传值会造成对象的切除, 切除派生类对象相对于基类对象多出来的部分, 造成最终调用的函数是基类的函数, 而不是我们想要的派生类中的覆盖版本.

参考文献: Sams.Teach.Yourself.Cplusplus.in.One.Hour.a.Day.8th.Edition.

©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页