国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

C++基礎(chǔ)語法(五)繼承——萬字總結(jié),干貨滿滿

smartlion / 3017人閱讀

摘要:繼承方式繼承方式限定了基類成員在派生類中的訪問權(quán)限,包括公有的私有的和受保護的。所以子類給父類引用賦值也是可以的,相當(dāng)于給子類對象中繼承的父類部分起了別名。如圖成員函數(shù)也是如此,當(dāng)子類與父類具有函數(shù)名相同的函數(shù)時,還是符合就近原則。

繼承是什么、為什么會出現(xiàn)繼承

1、什么樣的場景會使用繼承

xxxx我們在寫代碼的時候可能會出現(xiàn)這樣的情況,就是,我們在定義各種類的時候,可能不同的類中會出現(xiàn)大量完全相同的重復(fù)成員,這樣就造成了一定的代碼冗余。舉一個例子

無論是Student還是Teacher,他們作為人,姓名年齡都是他們的基本信息,如果每一個類都重復(fù)這些成員變量,這就導(dǎo)致了代碼的冗余。當(dāng)不同的類有相同的基本屬性,也就意味著有相同的成員。為此,就設(shè)計出了繼承來解決這個問題

2、什么是繼承

xxxx繼承(Inheritance)可以理解為一個類從另一個類獲取成員變量和成員函數(shù)的過程。這是一種很重要的代碼復(fù)用手段,繼承能夠使類在原有特性上進行擴展。繼承是類在設(shè)計層次上的一種復(fù)用。

3、繼承的語法

我先直接給出一個樣例:

這就是基本的語法,還是比較容易記住的。

繼承方式

xxxx繼承方式限定了基類成員在派生類中的訪問權(quán)限,包括 public(公有的)、private(私有的)和 protected(受保護的)。
xxxx繼承方式也可以不寫,使用默認(rèn)的。class類默認(rèn)的繼承方式是private,struct類默認(rèn)繼承方式是public。

1、訪問修飾限定符的作用

xxxx一直沒有整理過訪問限定修飾符作用,現(xiàn)在我們已經(jīng)學(xué)完了它的作用,借此機會將其整理一下,讓大家能夠深刻理解。

(1)修飾類中成員

public(公開):能夠使成員在類內(nèi)類外都可以被直接訪問
protected(保護):能夠使成員只能在類內(nèi)被訪問,而不能在類外被直接訪問
private(私有):能夠使成員只能在類內(nèi)被訪問,而不能在類外被直接訪問

只有public才能在類外被直接訪問,但是,三種都可以在類內(nèi)被直接訪問

(2)修飾繼承方式

繼承方式/基類成員public成員protected成員private成員
public繼承publicprotected不可見
protected繼承protectedprotected不可見
private繼承privateprivate不可見

(1)我們發(fā)現(xiàn),繼承之后成員的訪問權(quán)限 = min{父類成員訪問權(quán)限,繼承方式}
(2)不可見:在用子類訪問時,在子類內(nèi)、外都不可以訪問到。但是可以通過父類訪問。舉例

(3)這就體現(xiàn)出了protected的作用,單純考慮類中的作用,protected和private并沒有什么大的區(qū)別,但是在繼承這里,private會使子類對成員不可見,但是protected只會讓類外不可直接訪問,子類中還是可以直接訪問
(4)在實際應(yīng)用中,幾乎不會見到把父類的成員設(shè)置為private的現(xiàn)象。

基類/派生類對象賦值兼容問題(切割問題)

1、基類/派生類對象賦值兼容的基本概念

我們先看一個現(xiàn)象

xxxx我們在這里發(fā)現(xiàn),子類可以賦值給父類,但是父類不可以賦值給子類。這里就要介紹一個概念,就是**基類/派生類對象賦值兼容(切割)**下面節(jié)省,都叫切割
xxxx什么是“切割”?我們來看個圖

2、其他類型的切割

xxxx剛剛我們講到的是對象賦值給對象,我們只能將子類對象內(nèi)容賦值給父類對象。
xxxx但是除了這種“對象<>對象之間的”我們還有別的方法

指針賦值


同上述類似,傳遞指針時,也只能將子類的地址傳給父類的指針,此時該指針解引用只能訪問到父類所含有的內(nèi)容。

引用賦值

由于引用的底層就是指針,所以指針能夠完成的,引用一般也可以。所以子類給父類引用賦值也是可以的,相當(dāng)于給子類對象中繼承的父類部分起了別名。此時父類的引用只能訪問父類的成員。

繼承中的作用域

xxxx我們都知道,在同一個作用域中,不可以定義相同的變量和函數(shù)(函數(shù)重載除外!!),但是在不同的域里確實可以存在的。那么在繼承中,子類能否定義一個與父類相同的成員?
xxxx其實還是比較簡單的,因為不同的類是屬于不同的作用域,因此是可以定義重名成員的。例如:

xxxx雖然可以定義,但是使用的時候,我們是使用的哪一個呢?我們可以驗證一下:

我們發(fā)現(xiàn),A類的對象使用了A類自己的對象(這一點是很正常的)
B類的對象使用了子類的,并沒有使用父類的。其實,這一點也很好解釋,那就是,作用域一直是保證就近原則,在B類中有自己的_a,那么就會首先使用自己的,而不是父類的。
xxxx如果此時我們需要在子類對象中使用父類的同名的變量,我們就需要借助域作用限定符來指定作用域,從而訪問到我們所需的哪一個變量。如圖:

xxxx成員函數(shù)也是如此,當(dāng)子類與父類具有函數(shù)名相同的函數(shù)時,還是符合就近原則。但是這里就要介紹一個概念就是隱藏/遮蔽

隱藏/遮蔽

遮蔽的概念及理解

xxxx如果派生類中的成員((包括成員變量和成員函數(shù)))和基類中的成員重名,那么就會遮蔽從基類繼承過來的成員。所謂遮蔽,就是在派生類中使用該成員(包括在定義派生類時使用,也包括通過派生類對象訪問該成員)時,實際上使用的是派生類新增的成員,而不是從基類繼承來的。舉個例子:

xxxx但是,如果我們就是想要讓子類對象使用父類中的同名對象呢?**域作用限定符指定!!**如圖:

遮蔽與函數(shù)重載

xxxx這個問題其實也是許多學(xué)習(xí)者困惑的地方,我也是仔細(xì)看了C語言中文網(wǎng)的詳細(xì)解釋才發(fā)現(xiàn)了這個問題!
xxxx函數(shù)重載是指在同一個作用域中,函數(shù)名相同,參數(shù)列表不同的函數(shù)之間形成函數(shù)重載
xxxx但是在遮蔽中,我在上面闡述概念的時候,1、沒有拋開子類和父類(因此不屬于同一個作用域)2、并沒有提及參數(shù)的問題,只有函數(shù)名相同,并沒有對參數(shù)提任何要求~


xxxx這就是繼承中作用域的講解!

派生類的默認(rèn)成員函數(shù)

1、構(gòu)造函數(shù)

xxxx我們先來看一個現(xiàn)象

xxxx我們發(fā)現(xiàn),在子類中無法初始化父類的成員變量,爆出“XXX不是基或成員”、
xxxx但是我們再看一個場景

xxxx我們發(fā)現(xiàn),當(dāng)我們創(chuàng)建一個子類對象的時候,在調(diào)用構(gòu)造函數(shù)的初始化列表時候,編譯器會先自動調(diào)用父類的默認(rèn)構(gòu)造函數(shù)再去初始化子類的剩余新增內(nèi)容有個大前提,就是父類必須要默認(rèn)構(gòu)造函數(shù),這樣編譯器才會自動調(diào)用。其實這就表明,在子類中將父類的內(nèi)容看做一個整體,要去初始化父類的內(nèi)容,就要直接去調(diào)用父類的構(gòu)造函數(shù)整體初始化。就好像我們在子類中聲明了一個Person這個自定義類型的成員變量一樣。(構(gòu)造函數(shù)對于自定義類型會自動調(diào)用它的構(gòu)造函數(shù)初始化)

xxxx但是,如果父類沒有默認(rèn)構(gòu)造函數(shù),就需要我們顯示調(diào)用構(gòu)造函數(shù),方法如下:

2、拷貝構(gòu)造

xxxx其實拷貝構(gòu)造跟構(gòu)造函數(shù)是幾乎一樣的。如果有默認(rèn)的拷貝構(gòu)造,那子類中的拷貝構(gòu)造會直接調(diào)用默認(rèn)的拷貝構(gòu)造函數(shù),如果沒有,就需要我們?nèi)ワ@示調(diào)用。

xxxx但是細(xì)心的同學(xué)會發(fā)現(xiàn)為啥我們?nèi)タ截悩?gòu)造Person,你給它傳了一個Student的對象??
xxxx記不記得剛剛提到的“切割”,父類對象是可以接受子類對象的賦值的,在這里就有這樣非常好的應(yīng)用!!

3、operator=( )

xxxx賦值重載與上面類似,也需要在子類賦值重載中調(diào)用父類的賦值重載。如圖:
注:我們?nèi)ヅ苓@個賦值重載的代碼一定會有一個bug,其實也不是很難找出,但是我認(rèn)為不少人還是會小掉進這個溝里,才能再爬出來

還記不記得剛剛講的“遮蔽”問題,子類,父類都有operator=這個函數(shù),所以就產(chǎn)生了“遮蔽”,這就導(dǎo)致了,我們會調(diào)用子類的operator=,就會一直重復(fù)無限調(diào)用子類的operator=,發(fā)生StackOverFlow(棧溢出)。
xxxx想要解決這個問題就要指明作用域

4、析構(gòu)函數(shù)

xxxx我們按照之前的觀點,我們要析構(gòu),就要顯示調(diào)用父類的析構(gòu)函數(shù),加入我們先這樣進行操作,看看會發(fā)生什么。。。


我們發(fā)現(xiàn),他報錯了,原因是,在編譯器處理下,所有析構(gòu)函數(shù)都會被處理成一個變量名:destroy()。所以又會出現(xiàn)“遮蔽”的問題,所以我們就要指定作用域了!!

xxxx更改后:

xxxx但是,我們又發(fā)現(xiàn)了一個問題,就是為啥會先后調(diào)用兩次父類的析構(gòu)?那我們再試一下,如果我們不去顯示調(diào)用父類析構(gòu)會發(fā)生什么。。。

xxxx我們發(fā)現(xiàn),這樣感覺就好多了,正常了,子類和父類都只調(diào)用了一次析構(gòu)函數(shù)。而且是先析構(gòu)子類,再析構(gòu)父類,這與我們剛剛講解的構(gòu)造函數(shù)完全一致,因為在構(gòu)造函數(shù)中,編譯器就會在初始化列表階段自動調(diào)用(先顯示調(diào)用)父類的構(gòu)造,再去構(gòu)造子類剩下的內(nèi)容。由于棧的FILO特性,先構(gòu)造的后析構(gòu),這里是完全吻合的。
xxxx因此,我們又得出結(jié)論對于析構(gòu)函數(shù),我們不需要顯示調(diào)用父類析構(gòu)函數(shù),會在子類析構(gòu)函數(shù)結(jié)束時自動調(diào)用父類的析構(gòu)函數(shù)!!

多繼承

單繼承與多繼承的概念

單繼承:一個子類只有一個直接父類

多繼承:一個子類有兩個或兩個以上的直接父類

菱形繼承

xxxx菱形繼承不好解釋,直接看圖就可以看明白

菱形繼承的坑

菱形繼承有兩個很明顯的問題:1、數(shù)據(jù)冗余。2、二義性

1、數(shù)據(jù)冗余

xxxxD類繼承了B和C,但是B和C都繼承了A,所以相當(dāng)于D類中有兩份A的數(shù)據(jù),這兩份數(shù)據(jù)都要儲存在D類中,就會導(dǎo)致不必要的空間浪費。

2、二義性

xxxx當(dāng)我們?nèi)ソoA類中_a賦值的時候,編譯器不知道是給B類繼承的A的_a賦值還是C類中的,就會產(chǎn)生歧義。

但是這個問題我們可以通過域作用限定符來限定作用域。例如:

虛繼承

xxxx其實二義性還不是一個大問題,至少我們還有方法去解決,但是這個數(shù)據(jù)冗余的問題就是底層方面的了,我們是無法解決的。所以就出現(xiàn)了虛繼承來解決這個問題。
xxxx在B和C類中添加virtual關(guān)鍵字來實現(xiàn)虛繼承就可以解決這個問題。

終極問題:C++如何通過虛繼承解決數(shù)據(jù)冗余以及二義性

xxxx到底編譯器底層是怎樣實現(xiàn)用virtual解決數(shù)據(jù)冗余的呢?(數(shù)據(jù)冗余與二義性其實是一回事,當(dāng)數(shù)據(jù)冗余解決了,二義性自然也就解決了!!)
沒加virtual時

我們很容易看到,B類與C類是完全獨立的,所以是有兩份A類(B與C的前后順序與繼承順序有關(guān))


加virtual時

xxxx我們把這個奇怪的數(shù)字作為地址查詢,得到以下結(jié)果

對比&D的到的圖,我們發(fā)現(xiàn)20和12是有一定意義的!!
20是就是B類相對于公共出來的A類的偏移量(4字節(jié)5個位置)
而12同樣也是C類相對于公共出來A類的偏移量(4字節(jié)
3個位置)

xxxx總之,當(dāng)使用虛繼承后,就會把冗余重復(fù)的類“提取出來”,多帶帶放在一起,這樣就只有一個A類了,就不會出現(xiàn)數(shù)據(jù)的冗余,也就不會有二義性了!!!

總結(jié)

繼承作為面向?qū)ο笳Z言的三大特性之一還是非常重要的。但是其實除了這個菱形繼承和虛繼承比較難搞之外,繼承還是比較還理解的,然后重點是把語法和規(guī)律稍微記一下,還是比較容易上手的。其實一般情況我覺得也很少會出現(xiàn)菱形繼承的情況。重難點還是接下來的“多態(tài)”,我也是一直在啃這個硬骨頭,還是比較難理解的。下面我也會總結(jié)出來“多態(tài)”的知識,希望大家保持關(guān)注!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/122332.html

相關(guān)文章

  • SegmentFault 技術(shù)周刊 Vol.40 - 2018,來學(xué)習(xí)一門新的編程語言吧!

    摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...

    caspar 評論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.40 - 2018,來學(xué)習(xí)一門新的編程語言吧!

    摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...

    nihao 評論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.40 - 2018,來學(xué)習(xí)一門新的編程語言吧!

    摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...

    Drummor 評論0 收藏0
  • 爆肝1萬字c++入門綜合》

    摘要:大家好,今天屁孩君給大家?guī)砣腴T綜合。年,標(biāo)準(zhǔn)委員會發(fā)布了語言的第一個國際標(biāo)準(zhǔn),該標(biāo)準(zhǔn)即為大名鼎鼎的。年,標(biāo)準(zhǔn)委員會發(fā)布了一份技術(shù)報告,詳細(xì)說明了計劃引入的新特性。年月日,經(jīng)過標(biāo)準(zhǔn)委員投票,標(biāo)準(zhǔn)獲得一致通過。 ...

    _Dreams 評論0 收藏0
  • 0基礎(chǔ)C語言保姆教學(xué)——第節(jié) 數(shù)組

    摘要:關(guān)注我,訂閱專欄基礎(chǔ)語言保姆教學(xué),就可以持續(xù)讀到我的文章啦本文為萬字長文,滿滿干貨。那么,上面的代碼所運行的結(jié)果就是一維數(shù)組的使用使用即可以訪問并可以修改,即可讀可寫。 大家好~~~我是開心學(xué)編程,學(xué)到無極限的@jxwd? 寫在前面: 各位小伙伴還在為C語言的學(xué)習(xí)而苦惱嘛? 還在為...

    RobinQu 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<