C++中的多重繼承(一)


1,C++ 中是否允許一個類繼承自多個父類?

    1,可以;

    2,這種情況就是多重繼承;

    3,多重繼承的表象就是一個類有多個父類;

    4,這是 C++ 非常特別的一個特性,在其他的程序設計語言中比如 C#、Java、Object Pascal 中都只支持單重繼承;

   

2,C++ 支持編寫多重繼承的代碼:

    1,一個子類可以擁有多個父類;

    2,子類擁有所有父類的成員變量;

    3,子類繼承所有父類的成員函數;

    4,子類對象可以當作任意父類對象使用;

   

3,多重繼承的語法規則:

    1,代碼示例:

1 class Derived : public BaseA, public BaseB, public BaseC
2 {
3     // ...
4 };

    2,多重繼承的本質與單繼承相同;

   

4,多重繼承問題一編程實驗:

  1 #include <iostream>
  2 #include <string>
  3 
  4 using namespace std;
  5 
  6 class BaseA
  7 {
  8     int ma;
  9     
 10 public:
 11     BaseA(int a)
 12     {
 13         ma = a;
 14     }
 15     
 16     int getA()
 17     {
 18         return ma;
 19     }
 20 };
 21 
 22 class BaseB
 23 {
 24     int mb;
 25     
 26 public:
 27     BaseB(int b)
 28     {
 29         mb = b;
 30     }
 31     
 32     int getB()
 33     {
 34         return mb;
 35     }
 36 };
 37 
 38 class Derived : public BaseA, public BaseB
 39 {
 40     int mc;
 41     
 42 public:
 43     Derived(int a, int b, int c) : BaseA(a), BaseB(b)  // 初始化列表中同時調用父類的構造函數;
 44     {
 45         mc = c;
 46     }
 47     
 48     int getC()
 49     {
 50         return mc;
 51     }
 52     
 53     void print()
 54     {
 55         cout << "ma = " << getA() << ", "
 56              << "mb = " << getB() << ", "
 57              << "mc = " << mc << endl;
 58     }
 59 };
 60 
 61 int main()
 62 {
 63     cout << "sizeof(Derived) = " << sizeof(Derived) << endl;    // 12
 64     
 65     Derived d(1, 2, 3);
 66     
 67     d.print();
 68     
 69     cout << "d.getA() = " << d.getA() << endl;  // 1
 70     cout << "d.getB() = " << d.getB() << endl;  // 2
 71     cout << "d.getC() = " << d.getC() << endl;  // 3
 72     
 73     cout << endl;
 74     
 75     BaseA* pa = &d;
 76     BaseB* pb = &d;
 77     
 78     cout << "pa->getA() = " << pa->getA() << endl;  // 1
 79     cout << "pb->getB() = " << pb->getB() << endl;  // 2
 80     
 81     cout << endl;
 82     
 83     void* paa = pa;
 84     void* pbb = pb;
 85     
 86     
 87     if( paa == pbb )
 88     {
 89         cout << "Pointer to the same object!" << endl; 
 90     }
 91     else
 92     {
 93         cout << "Error" << endl;  // 打印 Error;
 94     }
 95     
 96     cout << "pa = " << pa << endl;  // 0xbfe7e304
 97     cout << "pb = " << pb << endl;  // 0xbfe7e308
 98     cout << "paa = " << paa << endl;  // 0xbfe7e304
 99     cout << "pbb = " << pbb << endl;   // 0xbf7e308
100     
101     return 0;
102 }

   

5,通過多重繼承得到的對象可能擁有“不同地址”:

    1,解決方案:無;

    2,多重繼承成員變量排布:

 

       1,指向同一個對象的不同位置;

       2,不方便開發了,因為我們一般比較這兩個指針是否相同來判斷是否指向同一個對象;

       3,這里兩個地址值不同依然可能指向同一個對象,情況變得非常復雜;

   

6,多重繼承可能產生冗余的成員:

 

    1,Doctor 這個類有兩個 m_name,兩個 m_age;

   

7,多重繼承問題二編程實驗:

    1,描述 本文6 中類圖:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class People
 7 {
 8     string m_name;
 9     int m_age;
10 public:
11     People(string name, int age)
12     {
13         m_name = name;
14         m_age = age;
15     }
16     void print()
17     {
18         cout << "Name = " << m_name << ", "
19              << "Age = " << m_age << endl;
20     }
21 };
22 
23 class Teacher : virtual public People
24 {
25 public:
26     Teacher(string name, int age) : People(name, age)
27     {
28     }
29 };
30 
31 class Student : virtual public People
32 {
33 public:
34     Student(string name, int age) : People(name, age)
35     {
36     }
37 };
38 
39 class Doctor : public Teacher, public Student
40 {
41 public:
42     Doctor(string name, int age) : Teacher(name, age + 1), Student(name, age), People(name, age)
43     {      // 如果在這里沒有調用 People(name, age),編譯器會在這一樣顯示如下錯誤:
44        // error: no matching function for call to 'People::People()'
45         // note: candidates are: People::People(std::string, int)  這是在父類構造的一行;
46     }    // note: People::People(const People&) ,這個編譯器提供,在類最開始那一行;
47 };
48 
49 int main()
50 {
51     Doctor d("Delphi", 33);
52     
53     d.print();  // 未有虛繼承時,編譯器顯示:error: request for member 'print' is  ambiguous
54           //  error: candidates are: void People::print()
55                 //  error:                 void People::print()
56     /* 未有虛繼承時,可以這樣分作用域分辨符來繼承 */
57     d.Teacher::print();  // Name = Delphi, Age = 33;
58     d.Student::print();  // Name = Delphi, Age = 33;
59     
60     return 0;
61 }

   

8,多重繼承關系出現閉合時將產生數據冗余的問題:

    1,解決方案:虛繼承;

    2,代碼示例:

1 class People {};
2 class Teacher : virtual public People {};
3 class Student : virtual public People {};
4 class Doctor : public Teacher, public Student {};

      

9,多重繼承的問題二:

    1,虛繼承能夠解決數據冗余問題;

   2,中間層父類不再關心頂層父類的初始化;

       1,規則不清晰;

       2,當今的軟件產品,動則幾十萬行代碼,業務邏輯已經很復雜了,我們希望編程語言越簡單越好,不希望幾套標准,這樣的話,只會造成生成效率的低下和致命的 bug;

       3,工程中可能是很多層繼承,這樣找的很麻煩,可以幾班解決;

   3,最終子類必須直接調用頂層父類的構造函數;

  

10,問題:

    1,當架構設計需要繼承時,無法確定使用直接繼承還是虛繼承;

       1,開發者感覺增加了開發時間;

       2,架構設計時,無法知道開發者是否會多重繼承;

       3,都做成虛繼承的時候,多重繼承加虛繼承太過復雜,影響效率和移植性(不同編譯器可能有不同實現方式);

       4,多重繼承只適合學術研究,工程一般不使用;

   

11,小結:

    1,C++ 支持多重繼承的編程方式;

       1,除了 C++ 支持多重繼承,基本上其它語言並不支持;

    2,多重繼承容易帶來問題:

       1,可能出現“同一個對象的地址不同”的情況;

       2,虛繼承可以解決數據冗余的問題;

       3,虛繼承使得架構設計可能出現問題;


免責聲明!

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



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