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個字節

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM