zoukankan      html  css  js  c++  java
  • C++虚继承

    什么是虚继承

    子类在继承父类时,在声明前加virtual关键字,这就是虚继承
    例:

    class A
    {
      //......
    }
    
    class B:virtual public A
    {
      //.......
    }
    

    什么时候需要使用虚继承

    在多重继承时,正常情况下子类对象将拥有继承链上所有父类对应的部分,但是如果两个父类都继承了同一个类,
    那么在子类将拥有两份祖父类的数据,比如菱形继承:
    20190804190545.png

     
    下面我以四个简单类来分析其内存结构:

    class CFuniture
    {
      int m_nFun;
    public:
      CFuniture()
      {
        m_nFun = 0;
      }
    
      virtual ~CFuniture()
      {
    
      }
    
      virtual void FunitureName()
      {
        cout << "CFuniture::FunitureName()" << endl;
      }
    };
    
    
    class CSofa : public CFuniture
    {
      int m_nSofa;
    public:
    
      virtual void Sit()
      {
        cout << "CSofa::Sit()" << endl;
      }
    
      CSofa()
      {
        m_nSofa = 1;
      }
    
      virtual ~CSofa()
      {
        cout << "~CSofa()" << endl;
      }
    };
    
    
    class CBed : public CFuniture
    {
      int m_nBed;
    public:
      CBed()
      {
        m_nBed = 2;
      }
    
      virtual void Sleep()
      {
        cout << "CBed::Sleep()" << endl;
      }
    
      virtual ~CBed()
      {
    
      }
    };
    
    class CSofaBed :public CSofa, public CBed
    {
      int m_nSofaBed;
    public:
      CSofaBed()
      {
        m_nSofaBed = 3;
      }
    
      virtual ~CSofaBed()
      {
        cout << "~CSofaBed()" << endl;
      }
    
      virtual void SleepAndSit()
      {
        cout << "CSofaBed::SleepAndSit()" << endl;
      }
    
      virtual void SitAndSleep()
      {
        cout << "CSofaBed::SitAndSleep()" << endl;
      }
    
      virtual void Sleep()
      {
        cout << "CSofaBed::Sleep()" << endl;
      }
    
      virtual void Sit()
      {
        cout << "CSofaBed::Sit()" << endl;
      }
    };
    
    
    int main(int argc, char **argv)
    {
      CSofaBed sofabed;
      return 0;
    }
    

    这里家具类CFuniture祖父类,沙发类CSofa和床类CBed都继承继承自CFuniture,沙发床类CSofaBed同时继承
    了CSofa和CBed,现在来看看CSofaBed对象的内存布局:
    20190805094512.png
    可以看出祖父类CFuniture在CSofaBed中有两份,这并非我们本意,我只想CSofaBed类对象中只有一份CFuniture
    类数据,那么可以在CSofa和CBed继承CFuniture时,加上virtual关键字表示和其它类共享CFuniture:

    class CSofa :virtual public CFuniture
    class CBed :virtual public CFuniture
    

    此时再来看看CSofaBed对象的内存布局:
    20190805095742.png
    从监视窗口可以看出CFunitrue类的数据有独立的一部分,但是CSofa和CBed中依旧有CFunitrue类的数据,
    其实这是VS的监视窗口为了更直观的显示继承体系,在CSofa和CBed中显示了CFunitrue类的数据,但是从
    内存窗口中可以看出CFunitrue类的数据只有一份;

     
    从上图可以看出CFunitrue类在CSofaBed子类中被独立出来,放在了对象的最尾部内存地址处,因为在CSofa和CBed以及CFunitrue中都有自己的虚函数,所以CSofaBed子类此时拥有三张属于自己虚表(和父类中的虚表不是同一个),另外CSofaBed子类自己新加的虚函数被追加到继承自CSofa虚表的后面,CSofaBed的析构函数被放到
    继承自祖父类CFunitrue的虚表中

     
    还可以从内存布局中看出CSofaBed的两个直接基类的虚表指针后面,还跟着两个指针:0x01259b68和0x01259bbc
    这两个指针是偏移指针,它们两指向相同的结构体,该结构体共8字节,前四个字节无意义,后四个字节记录了偏移
    指针距离CFunitrue类部分的字节数;从上图中可以看出sofbed对象中,CFunitrue类的部分位于0x0044FBDC
    开始的,CSofa类部分的偏移指针在0x0044FBC0处,两者之间间隔了0x18个字节;CBed类部分的偏移指针位于0x0044FBD0处,和CFunitrue类的部分间隔了0x0C个字节

  • 相关阅读:
    手写堆排序和归并排序
    海量数据处理
    HDU 1532 --&&-- POJ1273 dinic 算法
    POJ 3159 最短路 SPFA
    POJ 1459 网络流 EK算法
    8.14比赛j题 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87813#overview
    单链表---邻接表
    poj 1273 ---&&--- hdu 1532 最大流模板
    HDU 2603 二分匹配
    UVA 796 连通图求桥
  • 原文地址:https://www.cnblogs.com/UnknowCodeMaker/p/11301378.html
Copyright © 2011-2022 走看看