多重繼承、虛繼承與虛基類


一、多重繼承

單重繼承——一個派生類最多只能有一個基類
多重繼承——一個派生類可以有多個基類

class 類名: 繼承方式 基類1,繼承方式 基類2,…. {….};

派生類同時繼承多個基類的成員,更好的軟件重用
可能會有大量的二義性,多個基類中可能包含同名變量或函數

多重繼承中解決訪問歧義的方法:

基類名::數據成員名(或成員函數(參數表))

明確指明要訪問定義於哪個基類中的成員

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
 
#include <iostream>
using namespace std;

class Bed
{
public:
    Bed(int weight) : weight_(weight)
    {

    }
    void Sleep()
    {
        cout << "Sleep ..." << endl;
    }
    int weight_;
};

class Sofa
{
public:
    Sofa(int weight) : weight_(weight)
    {

    }
    void WatchTV()
    {
        cout << "Watch TV ..." << endl;
    }
    int weight_;
};

class SofaBed : public Bed, public Sofa
{
public:
    SofaBed() : Bed(0), Sofa(0)
    {
        FoldIn();
    }
    void FoldOut()
    {
        cout << "FoldOut ..." << endl;
    }
    void FoldIn()
    {
        cout << "FoldIn ..." << endl;
    }
};

int main(void)
{
    SofaBed sofaBed;
    //sofaBed.weight_ = 10; error
    //sofaBed.weight_ = 20; error

    sofaBed.Bed::weight_ = 10;
    sofaBed.Sofa::weight_ = 20;

    sofaBed.WatchTV();
    sofaBed.FoldOut();
    sofaBed.Sleep();

    return 0;
}

不能直接寫 sofaBed.weight_ = 10; 因為sofaBed 繼承了Sofa 和 Bed ,實際上有weigh_的兩份拷貝,這樣指向不明。只能通過

sofaBed.Bed::weight_ = 10; 訪問,但實際上一個sofaBed理應只有一個weight_,下面通過虛基類和虛繼承可以解決這個問題。


二、虛繼承與虛基類

當派生類從多個基類派生,而這些基類又從同一個基類派生,則在訪問此共同基類中的成員時,將產生二義性,可以采用虛基類來解決。

虛基類的引入

用於有共同基類的場合

聲明

以virtual修飾說明基類 例:class B1:virtual public BB

作用

主要用來解決多繼承時可能發生的對同一基類繼承多次而產生的二義性問題.

為最遠的派生類提供唯一的基類成員,而不重復產生多次拷貝

 

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
 
#include <iostream>
using namespace std;

class Furniture
{
public:
    Furniture(int weight) : weight_(weight)
    {
        cout << "Furniture ..." << endl;
    }
    ~Furniture()
    {
        cout << "~Furniture ..." << endl;
    }
    int weight_;
};

class Bed : virtual public Furniture
{
public:
    Bed(int weight) : Furniture(weight)
    {
        cout << "Bed ..." << endl;
    }
    ~Bed()
    {
        cout << "~Bed ..." << endl;
    }
    void Sleep()
    {
        cout << "Sleep ..." << endl;
    }

};

class Sofa : virtual public Furniture
{
public:
    Sofa(int weight) : Furniture(weight)
    {
        cout << "Sofa ..." << endl;
    }
    ~Sofa()
    {
        cout << "~Sofa ..." << endl;
    }
    void WatchTV()
    {
        cout << "Watch TV ..." << endl;
    }
};

class SofaBed : public Bed, public Sofa
{
public:
    SofaBed(int weight) : Bed(weight), Sofa(weight), Furniture(weight)
    {
        cout << "SofaBed ..." << endl;
        FoldIn();
    }
    ~SofaBed()
    {
        cout << "~SofaBed ..." << endl;
    }
    void FoldOut()
    {
        cout << "FoldOut ..." << endl;
    }
    void FoldIn()
    {
        cout << "FoldIn ..." << endl;
    }
};

int main(void)
{
    SofaBed sofaBed(5);
    sofaBed.weight_ = 10;


    sofaBed.WatchTV();
    sofaBed.FoldOut();
    sofaBed.Sleep();

    return 0;
}



此時只有一份weigh_,不存在訪問歧義的問題。

從輸出可以總結出:

1、虛基類的成員是由最遠派生類的構造函數通過調用虛基類的構造函數進行初始化的。
2、在整個繼承結構中,直接或間接繼承虛基類的所有派生類,都必須在構造函數的成員初始化表中給出對虛基類的構造函數的調用。如果未列出,則表示調用該虛基類的默認構造函數。
3、在建立對象時,只有最遠派生類的構造函數調用虛基類的構造函數,該派生類的其他基類對虛基類構造函數的調用被忽略。

 

參考:

C++ primer 第四版
Effective C++ 3rd
C++編程規范


免責聲明!

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



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