程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 多重繼承的二義性以及解決方法

多重繼承的二義性以及解決方法

編輯:C++入門知識

//多重繼承的二義性以及解決方法 //學習目的:了解類的繼承原理及多重繼承二義性的解決方法。 /* //本程序代碼來源《MFC權威剖析》p68 */ ////////////////////第一種多重繼承的二義性//////////////// class Employee { public:  char Name[40];  bool Sex; }; class Worker : public Employee { }; class Manager : public Employee { }; class Engineer : public Worker, public Manager { }; //Engineer的實例化對象內存中包含兩個Employee子對象,分別屬於Worker和Manager子對象, //這樣在該實例的內部就封裝了兩套員工個人檔案,顯然是錯誤的。 {  Engineer eng;  eng.Worker::Sex = true;  eng.Manager::Sex = false;//eng的性別即使男又是女 } /////////////////////解決辦法//////////////////////// //在父類存在共同雙親的情況下,可以通過虛擬基類來解決。 //虛擬基類的作用是:如果在一個派生類的繼承結構中,存在兩個同樣的虛擬基類,那麼 //該類的實例化對象內存中只存在一個虛擬基類的子對象。 //事例 class Employee { public:  char Name[40];  bool Sex; }; class Worker : public virtual Employee  //Employee { }; class Manager : public virtual Employee  //Employee { }; class Engineer : public Worker, public Manager { }; //這樣的繼承方式,虛擬基類的子對象不再包含在每個父類中,而是單獨存在。 //父類對象中存在一個指向其虛擬父類子對象的一個指針,該指針被稱為虛父類指針, //由編譯器生成。這樣就保證了在多重繼承時,子類實例中只存在一個虛擬基類的子對象。 //但同名的非虛擬基類的子對象沒有被合並。 /////////////////////第二種多重繼承的二義性//////////////// class ParentA { public:  void fun() {printf("%d\n", m_Value); }; private:  int m_Value; }; class ParentB { public:  void fun() {printf("%d\n", m_Value); }; private:  int m_Value; }; class Son : public ParentA, public ParentB { }; ///////////////////////解決辦法//////////////////////// //在父類沒有共同雙親的情況下,一般在子類中將名字沖突的成員重新定義, //以此解決二義性。 /////////////////////////////使用虛擬基類需要注意的問題//////////// [html]   #include "stdio.h"   class Base   {   public:    Base(){printf("Base is constructed  as default\n");}    Base(int i)     {      m_iValue=i;     printf("Base is constructed  in constructing list\n");    }    ~Base(){printf("Base is deconstructed\n");}        int GetiValue()const    {      return m_iValue;     }   private:    int m_iValue;   };   class ParentA :public virtual Base   {   public:    ParentA(){}    ParentA(int i,float f):Base(i)    { m_fValue=f; }    float GetfValue()const    {      return m_fValue;     }   private:    float m_fValue;   };   class ParentB :public virtual Base   {   public:    ParentB(){}    ParentB(int i,char c):Base(i)    { m_cValue=c; }        char GetcValue()const    {      return m_cValue;     }   private:    char m_cValue;   };   class Son:public ParentA,public ParentB   {   public:    Son(int i,float f,char c):ParentA(i,f),ParentB(i,c)    { }    void Output()    {     printf("son member is %d  %8.2f  %c\n",      GetiValue(),GetfValue(),GetcValue());    }   };      int main(int argc, char* argv[])   {    Son son(6,92.33,'D');    son.Output();      return 0;   }   /*輸出   Base is constructed  as default   son member is -858993460     92.33  D   ase is deconstructed   */   //由程序輸出可以看出,虛擬基類只被構造一次,銷毀一次,所以只存在一個子對象。   //但Base基類被調用的是默認構造函數,ParentA和ParentB對虛擬基類的構造無效。   //其實,為了保證虛擬基類只被構造一次,虛擬基類的構造函數不能按照傳統的方式調用,   //即不能被直接子類調用,而是由當前最底層次類的構造函數調用,該類被稱為最派生類。   //道理其實很簡單,和虛函數原理是一樣的。   //如果將Son的構造函數改成:   Son(int i, float f, char c):ParentA(i, f),ParentB(i, c),Base(i){}   /*則輸出   Base is constructed  as default   son member is 6     92.33  D   ase is deconstructed   */       //應用虛擬基類雖然解決了基類子對象重復問題,但還不能完全消除二義性的可能。 //如果兩個直接父類同時定義了同名的函數,則還會產生二義性。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved