• [C++对象模型][8]多重继承与虚函数表


    转载:

    [C++对象模型][8]多重继承与虚函数表

    一 多重继承

    1) 代码:

    Code
    #include <iostream>
    using namespace std;
    
    class B1
    {
    public:
        int x;
        virtual void v1(){ cout << "B1::v1" << endl; }
        void f1(){cout << "B1::f1" << endl; }
    };
    
    class B2
    {
    public:
        int y;
        virtual void v2(){ cout << "B2::v2" << endl; }
        void f2(){ cout << "B2::f2" << endl; }
    };
    
    class B3
    {
    public:
        int z;
        virtual void v3(){ cout << "B3::v3" << endl; }
        void f3(){ cout << "B3::f3" << endl; }
    };
    
    class D : public B1, public B2, public B3
    {
    public:
        int a;
        void v3(){ cout << "D::v3" << endl; }
        virtual void vD(){ cout << "D::vD" << endl; }
    };
    

      2)类图:

    3)VS2008的编译选项查看布局:

    4)可视化表示:

    5)代码验证:

    Code
    typedef void (*Fun)();
    
    void PrintMember(int *pI)
    {
        cout << *pI << endl;
    }
    void PrintVT(int *pVT)
    {
        while(*pVT != NULL)
        {
            (*(Fun*)(pVT))();
            pVT++;
        }
    }
    
    void PrintVTAndMember(B1 *pD)
    {
        int *pRoot = (int*)pD;
        int *pVTB1 = (int*)*(pRoot + 0);PrintVT(pVTB1);
        int *pMB1 = pRoot +1; PrintMember(pMB1);
        int *pVTB2 = (int*)*(pRoot + 2);PrintVT(pVTB2);
        int *pMB2 = pRoot +3; PrintMember(pMB2);
        int *pVTB3 = (int*)*(pRoot + 4);PrintVT(pVTB3);
        int *pMB3 = pRoot +5; PrintMember(pMB3);
    }
    
    void TestVT()
    {
        B1 *pB1 = new D();
        D *pD = dynamic_cast<D*>(pB1);
        pD->x = 10;
        pD->y = 20;
        pD->z = 30;
        pD->a = 40;
        PrintVTAndMember(pD);
        delete pD;
    }
    

      6) 验证代码运行结果:

    7)总结:

    与单继承相同的是所有的虚函数都包含在虚函数表中,所不同的多重继承有多个虚函数表,当子类对父类的虚函数有重写时,子类的函数覆盖父类的函数在对应的虚函数位置,当子类有新的虚函数时,这些虚函数被加在第一个虚函数表的后面。

    二 多重继承运行时类型转化

    1)代码验证:

    Code
    void TestDynamicCast()
    {
        B1 *pB1 = new D();
        cout << "B1:" << pB1 << endl;
        D *pD = dynamic_cast<D*>(pB1);
        cout << "D:"<< pD << endl;
        B2 *pB2 = dynamic_cast<B2*>(pB1);
        cout << "B2:" << pB2 << endl;
        B3 *pB3 = dynamic_cast<B3*>(pB1);
        cout << "B3:" << pB3 << endl;
        delete pD;
    }
    

      2)验证代码的运行结果:

    3)总结:

    从多重继承的内存布局,我们可以看到子类新加入的虚函数被加到了第一个基类的虚函数表,所以当dynamic_cast的时候,子类和第一个基类的地址相同,不需要移动指针,但是当dynamic_cast到其他的父类的时候,需要做相应的指针的移动。

    三 完!

  • 相关阅读:
    自我介绍 x
    第一次作业 x
    第二次作业 x
    第三次作业 x
    [C#] 用一种更优美的方式来替换掉又多又长的switchcase代码段
    通过设置光标形状实现拖拽控件时跟随一张透明图片的效果
    spring 入门笔记(一)
    PAT IO01. 表格输出(5)
    Maven 安装记
    华为机试 求最大三位数
  • 原文地址:https://www.cnblogs.com/sanghai/p/6525085.html
Copyright © 2020-2023  润新知