C 的多種繼承方式

2021-08-04 06:17:02 字數 3640 閱讀 7086

繼承的意義在於**可以復用,在原有的基礎上新增新功能就變成了新一代產品了(就像移動**發展史一樣,從大哥大到現在的智慧型手機,代代相傳添磚加瓦,單車變摩托,平房變別墅。究其本質是不變的),繼承也是為了多型服務的。

class的繼承分為單繼承,多繼承,菱形繼承,虛擬繼承,菱形虛擬繼承。

單繼承:

單繼承就是子類derived(派生類)繼承自乙個基類base (父類),其實就是子承父業。其在c++中的語法是:class derived:[繼承型別] base繼承型別有:public,protect, private。單繼承計算派生類大小方式是:sizeof(base)+派生類新增成員的大小

這三種繼承許可權的區別是:

在繼承中會有一些小小的問題,比如說在基類中有乙個成員變數或者成員函式,在派生類中也有乙個相同名稱的成員變數(與其型別無關)或者成員函式(與其引數無關),編譯器在處理這類問題時選擇同名隱藏(即隱藏基類中的成員函式或變數名),當呼叫這種相同名字的成員函式或變數時只會在派生類新增的成員中查詢(除非呼叫時加上作用域)。

多繼承:

多繼承相對於單繼承就是乙個派生類derived同時繼承多個基類base。介個沒法用類似子承父業的例子解釋^_^…。它的語法是:class derived:[繼承型別] base1,[繼承型別] base2,在記憶體中儲存基類的成員變數時 ,先繼承誰誰的成員變數就在相對的低位址(對小端位元組序的vs而言)出存放(意思就是先繼承誰就先存放誰)。在單繼承中派生類新增成員存放在基類前。這裡的兩個繼承型別都得加,若不加則預設為以私有型別繼承。派生類的大小:sizeof(base1)+sizeof(base2)+派生類新增成員的大小

多繼承例:

class base1

;class base2

;class derived :public base2, public base1 //語法

;int

main

()

測試結果:

菱形繼承:

菱形繼承顧名思義,肯定和菱形有關,廢話不多說還是用圖來解釋吧。

sizeof(c1)+sizeof(c2)+派生類新增成員大小

菱形繼承例:

class base

;class c1 : public base

;class c2 :public base

;class derived : public c1, public c2

;int

main

()

測試結果

菱形繼承又出現了一些問題,就是它在不加訪問限定符的情況下訪問基類成員會出問題,編譯器不通過這種訪問(這時候編譯器就傻了,到底該訪問哪乙個呢~)。為了解決這個二義性問題又出現了菱形虛擬繼承。先來看看虛擬繼承

虛擬繼承

虛擬繼承為解決多重繼承出現的二義性問題而出現,在其派生類定義開始的地方先存放了乙個指標,這個指標指向了乙個偏移量表,這個偏移量表存放的是派生類成員相對於基類成員的偏移量,虛擬繼承的大小sizeof(base)+派生類新增成員大小+乙個virtual指標

虛擬繼承例:

class base

public:

int _b;

};class derived :virtual

public base

int _d;

};int

main

()

測試結果:

編譯器會自動合成預設建構函式的情況:

菱形虛擬繼承:

結合了虛擬繼承和菱形繼承,解決了菱形繼承的二義性問題。其派生類大小sizeof(c1)+sizeof(c2)+派生類新增成員的大小,菱形虛擬繼承的virtual關鍵字只能加在繼承基類時,因為只在繼承積累時才有二義性問題。虛擬繼承就不會在派生類中出現兩份基類的成員。

測試**:

class base

;class c1 : virtual

public base

;class c2 : virtual

public base

;class derived : public c1, public c2

;int

main

()

測試結果:

紅框是虛擬繼承自c1的virtual指標,它相對於自己的偏移量和相對於基類的偏移量分別是0和20位元組,藍框就是c2的virtual指標了。 總結

基類的private成員在派生類中是不能被訪問的,如果基類成員不想在類外直接被訪問,但需要 在派生類中能訪問,就定義為protected。可以看出保護成員限定符是因繼承才出現的。

public繼承是乙個介面繼承,保持is-a原則,每個父類可用的成員對子類也可用,因為每個子類 物件也都是乙個父類物件。

protected/private繼承是乙個實現繼承,基類的部分成員並非完全成為子類介面的一部分, 是 has-a 的關係原則,所以非特殊情況下不會使用這兩種繼承關係,在絕大多數的場景下使用的 都是公有繼承。私有繼承以為這is-implemented-in-terms-of(是根據……實現的)。通常比 組合(composition)更低階,但當乙個派生類需要訪問基類保護成員或需要重定義基類的虛函 數時它就是合理的。

不管是哪種繼承方式,在派生類內部都可以訪問基類的公有成員和保護成員,基類的私有成員存 在但是在子類中不可見(不能訪問)。

使用關鍵字class時預設的繼承方式是private,使用struct時預設的繼承方式是public,不過最 好顯示的寫出繼承方式。

在實際運用中一般使用都是public繼承,極少場景下才會使用protetced/private繼承.

賦值相容規則–public繼承

子類物件可以賦值給父類物件(切割/切片)

父類物件不能賦值給子類物件

父類的指標/引用可以指向子類物件

子類的指標/引用不能指向父類物件(可以通過強制型別轉換完成)

友元與繼承

友元關係不能繼承,也就是說基類友元不能訪問子類私有和保護成員。 

繼承與靜態成員

基類定義了static成員,則整個繼承體系裡面只有乙個這樣的成員。無論派生出多少個子類,都只有 乙個static成員例項。

繼承的多種方式

常用的繼承方法 1.原生繼承 抽取共同點 人類 function people name,age,people.prototype.say function people.prototype.breath function 學生類 function student name,age,studentn...

JavaScript繼承的多種方式

1.原型鏈繼承 function a firstname a.prototype.getfirstname function function b lastname b.prototype newa 遠 b.prototype.getlastname function var person newb...

Class多種繼承方式

class 的多種繼承方式 繼承1 原型鏈繼承 子類的prototype為父類的例項 function person person.prototype.printname function function student student.prototype newperson student.pr...