多重继承、虚继承与虚基类
一、多重繼承
單重繼承——一個派生類最多只能有一個基類
多重繼承——一個派生類可以有多個基類
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++編程規范
總結
以上是生活随笔為你收集整理的多重继承、虚继承与虚基类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot与thymeleaf
- 下一篇: 《数据科学家访谈录》读书笔记