• <span id="qootd"></span>
      1. <track id="qootd"></track><acronym id="qootd"></acronym>

        多重繼承的先后問題上節最后的例子是為下面討論一個被稱之為“菱形問題”作鋪墊的,在Java中沒有多重繼承,也許沒有這種現象,C++中很容易出現。由一個基類派生出兩個類出來,以后新定義一個類,并從這兩個類多重繼承,這樣就出現菱形問題了。也就是說,基類的公有或保護成員,必然被兩個派生類同時繼承,這兩個類同時派生一個新類時,同名成員就產生了沖突。

        下面我們先從簡單問題入手,先不要看結果圖,考慮一下結果應該是什么。小雅當初認為三行輸出的ID都應為“WD8503025”,但事實不是這樣。

        1. #include <iostream>
        2. #include <string>
        3. using namespace std;
        4.  
        5. class CBase {
        6. public:
        7. string id;
        8. };
        9.  
        10. class CDerive1 : public CBase {
        11. public:
        12. void show1() {
        13. cout << "CDerive1: " << id << endl;
        14. }
        15. };
        16.  
        17. class CDerive2 : public CBase {
        18. public:
        19. void show2() {
        20. cout << "CDerive2: " << id << endl;
        21. }
        22. };
        23.  
        24. class CSon : public CDerive2, public CDerive1 { };
        25.  
        26. int main ( )
        27. {
        28. CSon s;
        29. s.CDerive1::id = "WD8503026";
        30. s.CDerive2::id = "WD8503027";
        31. s.CBase::id = "WD8503025";
        32. s.show1();
        33. s.show2();
        34. cout << "BASE: " << s.CBase::id << endl;
        35.  
        36. return 0;
        37. }

        運行結果:
        CDerive1: WD8503026
        CDerive2: WD8503025
        BASE: WD8503025

        通過設置斷點不難看出,當前實例是CBase的“孫子”,而“父親”有2個,每個“父親”都將“爺爺”復制了一份。如果不指定哪個“父親”的“父親”,默認將第一個繼承的“父親”的“父親”當作“爺爺”。上例中先繼承CDerive2類,所以31行和34行的“s.CBase::id”等價于“s.CDerive2::CBase::id”。

        實例地址的調查

        下面的例子是先定義一個“孫子”的實例,并將地址輸出。再將這個實例的地址分別賦給CDerive1和CDerive2類型的指針變量,并輸出指針地址。再將這2個地址分別賦給CBase的2個指針變量,并輸出其地址。大家仍然不看結果,考慮一下答案應該是什么?

        1. #include <iostream>
        2. #include <string>
        3. using namespace std;
        4.  
        5. class CBase {
        6. string id;
        7. public:
        8. void show() {
        9. cout << id << endl;
        10. }
        11. };
        12.  
        13. class CDerive1 : public CBase { };
        14.  
        15. class CDerive2 : public CBase { };
        16.  
        17. class CSon : public CDerive2, public CDerive1 { };
        18.  
        19. int main ( )
        20. {
        21. CSon s;
        22. cout << &s << endl;
        23. cout << "---------" << endl;
        24.  
        25. CDerive1 *pd1 = &s;
        26. cout << pd1 << endl;
        27. CDerive2 *pd2 = &s;
        28. cout << pd2 << endl;
        29. cout << "---------" << endl;
        30.  
        31. CBase *pb1 = pd1;
        32. cout << pb1 << endl;
        33. CBase *pb2 = pd2;
        34. cout << pb2 << endl;
        35.  
        36. //CBase *pb = &s; //編譯有錯
        37.  
        38. return 0;
        39. }

        運行結果:
        0035FB20
        ---------
        0035FB3C
        0035FB20
        ---------
        0035FB3C
        0035FB20

        從上例可以看出,由于2個“父親”因而復制出2個“爺爺”,2個“爺爺”的地址也不同。

        虛繼承

        解決以上問題只要用C++的“虛繼承”就可以了。“虛繼承”就是在實例中,基類不管繼承多少個,只復制一份。

        1.  #include <iostream>
        2. #include <string>
        3. using namespace std;
        4.  
        5. class CBase {
        6. public:
        7. string id;
        8. };
        9.  
        10. //因為虛繼承,CBase類在此不產生副本
        11. class CDerive1 : virtual public CBase {
        12. public:
        13. void show1() {
        14. cout << "CDerive1: " << id << endl;
        15. }
        16. };
        17.  
        18. //因為虛繼承,CBase類在此不產生副本
        19. class CDerive2 : virtual public CBase {
        20. public:
        21. void show2() {
        22. cout << "CDerive2: " << id << endl;
        23. }
        24. };
        25.  
        26. class CSon : public CDerive2, public CDerive1 { };
        27.  
        28. int main ( )
        29. {
        30. CSon s;
        31. s.CDerive1::id = "WD8503026";
        32. s.CDerive2::id = "WD8503027";
        33. s.CBase::id = "WD8503025";
        34. s.show1();
        35. s.show2();
        36. cout << "BASE: " << s.CBase::id << endl;
        37.  
        38. return 0;
        39. }

        運行結果:
        CDerive1: WD8503025
        CDerive2: WD8503025
        BASE: WD8503025

        因為2個“父親”都不產生“爺爺”的副本,所以“孫子”這兒就只有一個“爺爺”的副本。

        免責聲明:本文僅代表作者個人觀點,著作權歸作者所有。其原創性以及文中陳述文字和內容(包括圖片、視頻、附件等)未經本站證實,對本文以及其中全部或者部分內容、文字的真實性、完整性、及時性本站不作任何保證或承諾,請用戶僅作參考,并請自行核實相關內容。轉載作品務請注明出處,機構云平臺、個人云空間的建設權、管理權、所有權均歸實名機構和實名師生所有,與世界大學城無關。
        標簽:C++多重繼承的問題
        還能輸入 2000 個html字符
        色偷偷