zoukankan      html  css  js  c++  java
  • [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

  • 相关阅读:
    mui-popover显示、隐藏弹出菜单的方法
    mui使用总结
    js 原生 document.querySelectorAll document.getElementsByTagName document.querySelector document.getElementById的区别
    mui.min.js:7 Uncaught DOMException: Failed to execute 'send' on 'XMLHttpRequest': Failed to load
    三个div并排
    菜单栏伸缩(附jquery-1.12.1.js)
    验证码生成(点击就更换)
    IDEA算法导包后 import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey;报错
    IDEA加密算法(含所需jar包(commons-codec-1.11.jar ,bcprov-jdk15on-160.jar))
    1,eclipse导入项目jdk版本不一样解决方案 2,java报javax.servlet.jsp cannot be resolved to a type
  • 原文地址:https://www.cnblogs.com/itech/p/1399996.html
Copyright © 2011-2022 走看看