成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

smartlion / 3014人閱讀

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

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

1、什么樣的場(chǎng)景會(huì)使用繼承

xxxx我們?cè)趯?xiě)代碼的時(shí)候可能會(huì)出現(xiàn)這樣的情況,就是,我們?cè)诙x各種類的時(shí)候,可能不同的類中會(huì)出現(xiàn)大量完全相同的重復(fù)成員,這樣就造成了一定的代碼冗余。舉一個(gè)例子

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

2、什么是繼承

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

3、繼承的語(yǔ)法

我先直接給出一個(gè)樣例:

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

繼承方式

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

1、訪問(wèn)修飾限定符的作用

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

(1)修飾類中成員

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

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

(2)修飾繼承方式

繼承方式/基類成員public成員protected成員private成員
public繼承publicprotected不可見(jiàn)
protected繼承protectedprotected不可見(jiàn)
private繼承privateprivate不可見(jiàn)

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

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

基類/派生類對(duì)象賦值兼容問(wèn)題(切割問(wèn)題)

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

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

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

2、其他類型的切割

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

指針賦值


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

引用賦值

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

繼承中的作用域

xxxx我們都知道,在同一個(gè)作用域中,不可以定義相同的變量和函數(shù)(函數(shù)重載除外?。。?,但是在不同的域里確實(shí)可以存在的。那么在繼承中,子類能否定義一個(gè)與父類相同的成員?
xxxx其實(shí)還是比較簡(jiǎn)單的,因?yàn)椴煌念愂菍儆诓煌淖饔糜颍虼耸强梢远x重名成員的。例如:

xxxx雖然可以定義,但是使用的時(shí)候,我們是使用的哪一個(gè)呢?我們可以驗(yàn)證一下:

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

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

隱藏/遮蔽

遮蔽的概念及理解

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

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

遮蔽與函數(shù)重載

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


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

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

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

xxxx我們先來(lái)看一個(gè)現(xiàn)象

xxxx我們發(fā)現(xiàn),在子類中無(wú)法初始化父類的成員變量,爆出“XXX不是基或成員”、
xxxx但是我們?cè)倏匆粋€(gè)場(chǎng)景

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

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

2、拷貝構(gòu)造

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

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

3、operator=( )

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

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

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

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


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

xxxx更改后:

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

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

多繼承

單繼承與多繼承的概念

單繼承:一個(gè)子類只有一個(gè)直接父類

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

菱形繼承

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

菱形繼承的坑

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

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

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

2、二義性

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

但是這個(gè)問(wèn)題我們可以通過(guò)域作用限定符來(lái)限定作用域。例如:

虛繼承

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

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

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

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


加virtual時(shí)

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

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

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

總結(jié)

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

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/122332.html

相關(guān)文章

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

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

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

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

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

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

    Drummor 評(píng)論0 收藏0
  • 爆肝1萬(wàn)字c++入門(mén)綜合》

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

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

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

    RobinQu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<