9-4:C++多态之单继承和多继承中的虚函数表
发布日期:2021-05-14 14:14:38 浏览次数:22 分类:精选文章

本文共 2444 字,大约阅读时间需要 8 分钟。

在C++编程中,虚函数是一个非常重要的概念,尤其是在继承编程中。虚函数的存在使得类之间能够具有多态性,即同一函数名可以具有不同的实现,而具体调用的函数会根据对象的类型来确定。通过本文,我们将深入探讨虚函数表在单继承和多继承中的分别实现机制。

单继承中的虚函数表

在单继承体系中,子类继承基类时会自动继承基类的虚函数表。子类可以重写基类中的虚函数,而未被重写的虚函数则仍然存储在基类的虚函数表中。以下是一个典型的单继承示例:

// 基类A定义了两个虚函数fun1()和fun2()class A {public:    virtual void fun1() { cout << "A::fun1" << endl; }    virtual void fun2() { cout << "A::fun2" << endl; }private:    int _a = 1;};// 子类B继承自A,并重写了fun1(),同时定义了新的虚函数fun3()class B : public A {public:    virtual void fun1() { cout << "B::fun1" << endl; }    virtual void fun3() { cout << "B::fun3" << endl; }private:    int _b = 2;};

在实际执行程序时,由于B继承自A,B对象的虚函数表指针(VFunc Pointer, VFP)指向A类的虚函数表。具体到虚函数调用,同一函数名(如fun1)的最终执行地址将取决于对象类型。通过ILD工具(Jeffrey`s Instruction List Disassembler)可以观察类的虚函数表布局。

为了验证虚函数表的实际布局,我们可以编写以下程序:

// 完成该部分的代码示例如下,仅供参考int main() {    A a;    B b;    VFUN* va = (VFUN*)(*(int*)&a); // 获取A类的虚函数表指针    VFUN* vb = (VFUN*)(*(int*)&b); // 获取B类的虚函数表指针    printVtf(va); // 打印A类的虚函数表    printVtf(vb); // 打印B类的虚函数表    return 0;}

通过这种方式,我们可以清晰地看到不同类的虚函数表布局,并直接调用的虚函数行为。

多继承中的虚函数表

多继承扩展了单继承的功能,使得一个类可以同时继承自多个基类。在多继承的情况下,子类继承的虚函数表包含来自所有直接基类的虚函数。未被重写的虚函数存储在第一个直接基类的虚函数表中,而重写的虚函数则存储在新的虚函数表中。

考虑以下多继承示例:

// 基类Base1和Base2分别定义了func1()和func2()class Base1 {public:    virtual void func1() { cout << "Base1::func1" << endl; }    virtual void func2() { cout << "Base1::func2" << endl; }private:    int b1;};class Base2 {public:    virtual void func1() { cout << "Base2::func1" << endl; }    virtual void func2() { cout << "Base2::func2" << endl; }private:    int b2;};// 子类Derive同时继承自Base1和Base2,并重写func1(),定义新的func3()class Derive : public Base1, public Base2 {public:    virtual void func1() { cout << "Derive::func1" << endl; }    virtual void func3() { cout << "Derive::func3" << endl; }private:    int d1;};

在这种情况下,Derive类会继承两个虚函数表:

  • 第一个虚函数表来自Base1,包含Base1未被重写的虚函数。
  • 第二个虚函数表来自Base2,包含Base2未被重写的虚函数。
  • 通过虚函数表指针可以分别访问到这两个虚函数表,例如:

    // 完成该部分的代码示例如下,仅供参考int main() {    Derive d;    cout << sizeof(d) << endl; // 内联描述:输出对象的大小    // 打印第一个虚函数表(Base1部分)    void* vftBase1Ptr = (void*)(*((void*)(&d)) + Base1::vtOffset); // 假设vtOffset是Base1的起始虚函数表偏移    PrintVFT(vftBase1Ptr);    // 打印第二个虚函数表(Base2部分)    void* vftBase2Ptr = (void*)(*((void*)(&d)) + Base2::vtOffset); // 假设vtOffset是Base2的起始虚函数表偏移    PrintVFT(vftBase2Ptr);    return 0;}

    这种结构使得继承的多样性更加灵活,同时确保了虚函数的多态性。

    总结

    通过上述分析,我们可以清楚地看到虚函数表在C++中起到的关键作用。无论是单继承还是多继承,虚函数表都为继承类的多态性提供了技术支持,使得类之间能够有统一的接口定义,同时允许子类对接口进行个性化实现。在实际开发中,理解虚函数表的工作原理对于解决若干常见的编程难题至关重要。

    上一篇:3-1:类与对象之上篇之类的引入和类的定义以及访问限定符和封装还有对面向对象的理解
    下一篇:9-3:C++多态之多态的实现原理之虚函数表,虚函数表指针静态绑定和动态绑定

    发表评论

    最新留言

    初次前来,多多关照!
    [***.217.46.12]2025年04月17日 17时52分13秒