1. 程式人生 > 其它 >C++多繼承(多重繼承)

C++多繼承(多重繼承)

派生類都只有一個基類,稱為單繼承(Single Inheritance)。除此之外,C++也支援多繼承(Multiple Inheritance),即一個派生類可以有兩個或多個基類。
多繼承容易讓程式碼邏輯複雜、思路混亂,一直備受爭議,中小型專案中較少使用,後來的 JavaC#PHP 等乾脆取消了多繼承。
多繼承的語法也很簡單,將多個基類用逗號隔開即可。例如已聲明瞭類A、類B和類C,那麼可以這樣來宣告派生類D:

class D: public A, private B, protected C{
    //類D新增加的成員
}

D 是多繼承形式的派生類,它以公有的方式繼承 A 類,以私有的方式繼承 B 類,以保護的方式繼承 C 類。D 根據不同的繼承方式獲取 A、B、C 中的成員,確定它們在派生類中的訪問許可權。

多繼承下的建構函式

多繼承形式下的建構函式和單繼承形式基本相同,只是要在派生類的建構函式中呼叫多個基類的建構函式。以上面的 A、B、C、D 類為例,D 類建構函式的寫法為:

D(形參列表): A(實參列表), B(實參列表), C(實參列表){
    //其他操作
}

基類建構函式的呼叫順序和和它們在派生類建構函式中出現的順序無關,而是和宣告派生類時基類出現的順序相同。仍然以上面的 A、B、C、D 類為例,即使將 D 類建構函式寫作下面的形式:

D(形參列表): B(實參列表), C(實參列表), A(實參列表){
    //其他操作
}

那麼也是先呼叫 A 類的建構函式,再呼叫 B 類建構函式,最後呼叫 C 類建構函式。

下面是一個多繼承的例項:
  1. #include <iostream>
  2. using namespace std;
  3. //基類
  4. class BaseA{
  5. public:
  6. BaseA(int a, int b);
  7. ~BaseA();
  8. protected:
  9. int m_a;
  10. int m_b;
  11. };
  12. BaseA::BaseA(int a, int b): m_a(a), m_b(b){
  13. cout<<"BaseA constructor"<<endl;
  14. }
  15. BaseA::~BaseA(){
  16. cout<<"BaseA destructor"<<endl;
  17. }
  18. //基類
  19. class BaseB{
  20. public:
  21. BaseB(int c, int d);
  22. ~BaseB();
  23. protected:
  24. int m_c;
  25. int m_d;
  26. };
  27. BaseB::BaseB(int c, int d): m_c(c), m_d(d){
  28. cout<<"BaseB constructor"<<endl;
  29. }
  30. BaseB::~BaseB(){
  31. cout<<"BaseB destructor"<<endl;
  32. }
  33. //派生類
  34. class Derived: public BaseA, public BaseB{
  35. public:
  36. Derived(int a, int b, int c, int d, int e);
  37. ~Derived();
  38. public:
  39. void show();
  40. private:
  41. int m_e;
  42. };
  43. Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
  44. cout<<"Derived constructor"<<endl;
  45. }
  46. Derived::~Derived(){
  47. cout<<"Derived destructor"<<endl;
  48. }
  49. void Derived::show(){
  50. cout<<m_a<<", "<<m_b<<", "<<m_c<<", "<<m_d<<", "<<m_e<<endl;
  51. }
  52. int main(){
  53. Derived obj(1, 2, 3, 4, 5);
  54. obj.show();
  55. return 0;
  56. }
執行結果:
BaseA constructor
BaseB constructor
Derived constructor
1, 2, 3, 4, 5
Derived destructor
BaseB destructor
BaseA destructor

從執行結果中還可以發現,多繼承形式下解構函式的執行順序和建構函式的執行順序相反。

命名衝突

當兩個或多個基類中有同名的成員時,如果直接訪問該成員,就會產生命名衝突,編譯器不知道使用哪個基類的成員。這個時候需要在成員名字前面加上類名和域解析符::,以顯式地指明到底使用哪個類的成員,消除二義性。

修改上面的程式碼,為 BaseA 和 BaseB 類新增 show() 函式,並將 Derived 類的 show() 函式更名為 display():
  1. #include <iostream>
  2. using namespace std;
  3. //基類
  4. class BaseA{
  5. public:
  6. BaseA(int a, int b);
  7. ~BaseA();
  8. public:
  9. void show();
  10. protected:
  11. int m_a;
  12. int m_b;
  13. };
  14. BaseA::BaseA(int a, int b): m_a(a), m_b(b){
  15. cout<<"BaseA constructor"<<endl;
  16. }
  17. BaseA::~BaseA(){
  18. cout<<"BaseA destructor"<<endl;
  19. }
  20. void BaseA::show(){
  21. cout<<"m_a = "<<m_a<<endl;
  22. cout<<"m_b = "<<m_b<<endl;
  23. }
  24. //基類
  25. class BaseB{
  26. public:
  27. BaseB(int c, int d);
  28. ~BaseB();
  29. void show();
  30. protected:
  31. int m_c;
  32. int m_d;
  33. };
  34. BaseB::BaseB(int c, int d): m_c(c), m_d(d){
  35. cout<<"BaseB constructor"<<endl;
  36. }
  37. BaseB::~BaseB(){
  38. cout<<"BaseB destructor"<<endl;
  39. }
  40. void BaseB::show(){
  41. cout<<"m_c = "<<m_c<<endl;
  42. cout<<"m_d = "<<m_d<<endl;
  43. }
  44. //派生類
  45. class Derived: public BaseA, public BaseB{
  46. public:
  47. Derived(int a, int b, int c, int d, int e);
  48. ~Derived();
  49. public:
  50. void display();
  51. private:
  52. int m_e;
  53. };
  54. Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
  55. cout<<"Derived constructor"<<endl;
  56. }
  57. Derived::~Derived(){
  58. cout<<"Derived destructor"<<endl;
  59. }
  60. void Derived::display(){
  61. BaseA::show(); //呼叫BaseA類的show()函式
  62. BaseB::show(); //呼叫BaseB類的show()函式
  63. cout<<"m_e = "<<m_e<<endl;
  64. }
  65. int main(){
  66. Derived obj(1, 2, 3, 4, 5);
  67. obj.display();
  68. return 0;
  69. }
請讀者注意第 64、65 行程式碼,我們顯式的指明瞭要呼叫哪個基類的 show() 函式。