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

  • 相关阅读:
    安装lnmp 时如何修改数据库数据存储地址及默认访问地址
    ubuntu 设置root用户密码并实现root用户登录
    解决ubuntu 远程连接问题
    linux 搭建FTP服务器
    PHP 根据ip获取对应的实际地址
    如何发布自己的composer包
    使用composer安装composer包报Your requirements could not be resolved to an installable set of packages
    laravel 框架配置404等异常页面
    使用Xshell登录linux服务器报WARNING! The remote SSH server rejected X11 forwarding request
    IoTSharp 已支持国产松果时序数据库PinusDB
  • 原文地址:https://www.cnblogs.com/itech/p/1399996.html
Copyright © 2011-2022 走看看