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


    一 虚继承

    1) 代码:

    Code
    #include <iostream>
    using namespace std;

    class B
    {
    public:
        
    int i;
        
    virtual void vB(){ cout << "B::vB" << endl; }
        
    void fB(){ cout << "B::fB" << endl;}
    };

    class D1 : virtual public B
    {
    public:
        
    int x;
        
    virtual void vD1(){ cout << "D1::vD1" << endl; }
        
    void fD1(){ cout << "D1::fD1" << endl;}
    };

    class D2 : virtual public B
    {
    public:
        
    int y;
        
    void vB(){ cout << "D2::vB" << endl;}
        
    virtual void vD2(){ cout << "D2::vD2" << endl;}
        
    void fD2(){ cout << "D2::fD2" << endl;}
    };

    class GD :  public D1, public D2
    {
    public:
        
    int a;
        
    void vB(){ cout << "GD::vB" << endl;}
        
    void vD1(){cout << "GD::vD1" << endl;}
        
    virtual void vGD(){cout << "GD::vGD" << endl;}
        
    void fGD(){cout << "GD::fGD" << endl;}
    };

    2)类图:

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

    4)可视化表示:

    5)代码验证:(此时的虚函数表不是以NULL结尾,为什么?

    Code
    typedef void (*Fun)();

    void PrintMember(int *pI)
    {
        cout 
    << *pI << endl << endl;
    }
    void PrintVT(int *pVT)
    {
        
    while(*pVT != NULL)
        {
            (
    *(Fun*)(pVT))();
            pVT
    ++;
        }
    }

    void PrintMemberAndVT(GD *pGD)
    {
        
    int *pRoot = (int*)pGD;

        
    int *pD1VT = (int*)*(pRoot + 0); 
        (
    *(Fun*)(pD1VT))(); (*(Fun*)(pD1VT +1))();
        
    int *pVB = (int*)*(pRoot +1);  cout << "vbtable's adress:" << *pVB << endl;
        
    int *pX = (pRoot + 2); PrintMember(pX);

        
    int *pD2VT = (int*)*(pRoot + 3); 
        (
    *(Fun*)(pD2VT))();
        
    int *pVB2 = (int*)*(pRoot +4); cout << "vbtable's adress:" << *pVB2 << endl;
        
    int *pY = (pRoot + 5); PrintMember(pY);

        
    int *pA = (pRoot + 6); PrintMember(pA);

        
    int *pBVT = (int*)*(pRoot + 7); 
        (
    *(Fun*)(pBVT))();
        
    int *pI = (pRoot + 8); PrintMember(pI);
    }

    void TestVT()
    {
        B 
    *pB = new GD();
        GD 
    *pGD = dynamic_cast<GD*>(pB);
        pGD
    ->= 10;
        pGD
    ->= 20;
        pGD
    ->= 30;
        pGD
    ->= 40;
        PrintMemberAndVT(pGD);
        delete pGD;
    }

    6)验证代码结果:

    7)总结:

    虚继承,使公共的基类在子类中只有一份,我们看到虚继承在多重继承的基础上多了vbtable来存储到公共基类的偏移。

    二 虚继承运行时类型转化

    1)代码验证:

    Code
    void TestDynamicCast()
    {
        B 
    *pB = new GD();
        GD 
    *pGD = dynamic_cast<GD*>(pB);
        cout 
    << "GD:" << pGD << endl;
        D1 
    *pD1 = dynamic_cast<D1*>(pB);
        cout 
    << "D1:" << pD1 << endl;
        D2 
    *pD2 = dynamic_cast<D2*>(pB);
        cout 
    << "D2:" << pD2 << endl;
        cout 
    << "B:" << pB << endl;
    }

    2)验证代码结果:

    3)总结:

    还是从内存布局来看dynamic_cast时地址的变化,第一个基类的地址与子类相同,其他的基类和虚基类需要做偏移。

    三 完!


    作者:iTech
    微信公众号: cicdops
    出处:http://itech.cnblogs.com/
    github:https://github.com/cicdops/cicdops

  • 相关阅读:
    JS面试题(一)
    cookie、locakstorage、sessionstorage的区别
    BOM操作
    DOM表单(复选框)
    DOM表格操作
    Javascript的组成——EMACScript、DOM、BOM
    scrollto 到指定位置
    编写一个javscript函数 fn,该函数有一个参数 n(数字类型),其返回值是一个数组,该数组内是 n 个随机且不重复的整数,且整数取值范围是 [2, 32]。
    使用bluebird解决promise兼容性问题
    Mac 更改/usr/bin 目录权限失败
  • 原文地址:https://www.cnblogs.com/itech/p/1399996.html
Copyright © 2020-2023  润新知