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,虛繼承使得架構設計可能出現問題;