作為物件導向三大特性之一,繼承的好處是可以減少重複的**。比如,我們在建立乙個比較大的**時,**中有很多頁面,每個頁面其實是有一些相同的東西的,比如標題欄,導航欄還是廣告等等。如果我們在寫每個頁面時都把這些公共的部分重新寫一遍,**會非常累贅,我們可以把公共的部分封裝為乙個類(父類),後面的頁面去繼承這個類,這樣公共部分的**只需要寫一遍,後面需要繼承即可,便減少了許多**。
問題:從父類繼承過來的成員,哪些屬於子類物件中?
//父類(基類)
class
base
;//子類(派生類)
class
son:
public base
;void
test01()
列印結果為16
這裡主要是想驗證父類中私有成員是否被子類繼承下去了。列印結果說明答案是肯定的
進一步驗證
開啟visual studio developer command prompt
首先定位到當前cpp檔案的碟符
然後輸入cl/d1 reportsingleclasslayout檢視的類名 所屬檔名
注意cl(這個是大寫字母l的小寫l)
d1(這個是數字1)
子類繼承父類後,當建立子類物件,也會呼叫父類的建構函式
問題:父類和子類的構造和析構順序是誰先誰後?
class
base
~base()
};class
son:
public base
~son()
};void
test01()
列印結果:
結論:繼承中,例項化子類物件時,先呼叫父類建構函式,再呼叫子類建構函式,析構順序與構造順序是相反的
兩個派生類(子類)繼承同乙個基類(父類),又有某個類同時繼承這兩個派生類(子類)這種繼承稱為菱形繼承
假如現在有 a b c d四個類 以下就是菱形繼承
列印結果:這個很好理解,同名的成員變數 想要輸出的話加作用域區分即可
但是問題是如果我們想列印輸出d類中的資料 呢
d1.m_age //因為d1是d類例項化得來的
//所以想要輸出同名成員變數直接輸出即可
//無需加作用域區分
它會報錯,因為d類繼承了b,c 類,也就是說它繼承 了a類的m_age繼承了兩份。那麼就會出現二義性問題。它不知道是輸出b類的還是c類的。也就是說,我們只需要乙份資料即可,不能同時要兩份。因此,菱形繼承帶來的問題是子類繼承了兩份相同的資料,導致了資源浪費以及毫無意義
利用虛繼承可以解決菱形繼承的問題。語法很簡單`
//繼承前加上virtual關鍵字就變為了虛繼承
//此時它們的公共父類a就變為了虛基類(虛父類)
運用命令提示符檢視d類的物件模型:
結果如下:
這是沒有用到虛繼承時d類的物件模型 很顯然它繼承了兩份相同的資料,所以會出現二義性
分析之前先解釋兩個名詞:
vbptr(虛基類指標):
v:virtual(虛擬)
b:base(基類)
ptr:pointer(指標)
它指向的位址是乙個虛基類表
vbtable(虛基類表) :table是**的意思
裡面記錄了偏移量
分析如下:
顯然,當是虛繼承時,資料只有乙份了,它繼承於a類.d類在繼承b c類時,是繼承了兩個指標.它們對應的有相應的偏移量.比如b類vbptr初值為0它會找到對應的虛基類表,虛基類表中記錄的偏移量是8 那麼0 + 8 = 8 就會對應從a類繼承來的m_age,c類同理,vbptr初值是4,偏移量是4,4 + 4 = 8 它也能對應地找到m_age的位址.
C 繼承學習筆記
派生類從基類繼承了保護 protected 成員和公有 public 成員函式,但是繼承不了基類的過載建構函式。定義乙個如下基類 class counter counter operator counter n void reset int getcount int getnum counter c...
C 學習筆記 繼承
一 c 中的繼承方式會影響子類的對外訪問屬性 public 修飾的成員變數 方法 在類的內部 類的外部都能使用 protected 修飾的成員變數方法,在類的內部使用,在繼承的子類中可用 private 修飾的成員變數方法,只能在類的內部使用 二 private成員在子類中依然存在,但是卻無法訪問到...
c 學習筆記 繼承
虛基類 派生類繼承的時候使用virtual關鍵字繼承的基類。個人認為叫 虛繼承 更為具體直觀。使用虛基類可以消除由多繼承產生的二義性。派生類可以隱含的轉換為基類,反之則不行。可以使用using語句繼承基類的建構函式,預設情況不繼承基類的建構函式。在即有繼承又有組合的時候,建構函式的呼叫順序為 先呼叫...