前言 在上述教程中,我們已經(jīng)完成了?
C 相對(duì)于?
C語(yǔ)言來(lái)說(shuō)獨(dú)特的語(yǔ)法部分,在接下來(lái)的教程中,我們將敘述?
C 中面向?qū)ο蟮恼Z(yǔ)法特性。我們?cè)趯W(xué)習(xí)面向?qū)ο蟮倪@種編程方法的時(shí)候,常常會(huì)聽(tīng)到這三個(gè)詞,
封裝、繼承、派生 ,這也是面向?qū)ο缶幊痰娜筇匦?,在本?jié)我們將依次闡述封裝、繼承、派生的具體用法,在這里,我們先敘述的是
封裝 這個(gè)屬性的的相關(guān)內(nèi)容。下圖是關(guān)于?
封裝 ?這個(gè)特性所包含的一些內(nèi)容。
封裝 下圖就是封裝所具備的相關(guān)特性:
image-20210209204824118 那么上圖所示的
抽象出數(shù)據(jù)成員以及成員函數(shù) 具體的含義是什么呢,正如前面教程所述,在前面的教程里,我們選用一個(gè)?
Person類(lèi)來(lái)作為例子進(jìn)行講解,其中這個(gè)類(lèi)里我們有?
name以及
age,這個(gè)也就是我們抽象出來(lái)的數(shù)據(jù),那抽象出來(lái)的成員函數(shù)也就是前面教程講到的
setName()和
setAge()函數(shù),在設(shè)計(jì)這個(gè)類(lèi)的時(shí)候,會(huì)把這個(gè)類(lèi)的一些成員設(shè)置為私有的或者公有的,這也就是訪問(wèn)控制。具體的代碼如下所示:
/*?為了代碼簡(jiǎn)便,省略相關(guān)構(gòu)造函數(shù)以及析構(gòu)函數(shù),為的是展示封裝的特性*/ class ?Person ?{private : ????char ?*name; ????int ?age;public : ????Person() ????{ ????????cout ?<"Person" ?<endl ; ????????name?=?NULL ; ????} ????~Person() ????{ ????????cout ?<"~Person()" ?<endl ; ????????if ?(this ->name) ????????{ ????????????delete ?this ->name; ????????} ????} ????void ?setName (char ?*name) ???? { ????????if ?(this ->name)?{ ????????????delete ?this ->name; ????????} ????????this ->name?=?new ?char [strlen (name)? ?1 ]; ????????strcpy (this ->name,?name); ????} ????int ?setAge (int ?a) ???? { ????????if ?(a?0 ?||?a?>?150 ) ????????{ ????????????age?=?0 ; ????????????return ?-1 ; ????????} ????????age?=?a; ????????return ?0 ; ????} };繼承 繼承的含義就如其字面意思一樣,用更加專(zhuān)業(yè)的話來(lái)說(shuō),就是從
基類(lèi) 繼承相關(guān)屬性,而這個(gè)新的類(lèi)就叫做
派生類(lèi) 。下面這個(gè)示意圖也表明了繼承所帶來(lái)的代碼的簡(jiǎn)潔與方便。
image-20210209211013964 就如上述這張圖所示,一個(gè)人肯定具有名字和年齡這兩個(gè)屬性,那作為一個(gè)學(xué)生來(lái)講,他也必定具備名字和年齡這兩個(gè)屬性,那這個(gè)時(shí)候是要在?
Student類(lèi)里重新定義這些屬性么?顯然,因?yàn)橐肓死^承這個(gè)特性,只需要繼承
Person類(lèi),那么
Student就具備?
Person類(lèi)的相關(guān)屬性。在上述代碼的基礎(chǔ)上,我們?cè)黾尤缦滤镜拇a:
/*?注意是在上述代碼的基礎(chǔ)上?*/ class ?Student ?: ?public ?Person { };int ?main (int ?argc,?char ?**argv) { ????Student?s; ????s.setName("zhangsan" ); ????s.setAge(16 ); ????s.printInfo(); ????return ?0 ; }上述代碼中,
Student類(lèi)是繼承自?
Person類(lèi)的,我們可以看到在上述所示的
Student類(lèi)中,并沒(méi)有
setName和?
setAge的成員函數(shù),但是在定義的?
Student實(shí)例中,卻能夠適用?
setName和?
setAge的成員函數(shù),這也就說(shuō)明了?
Student類(lèi)已經(jīng)繼承了?
Person類(lèi)。
繼承后的訪問(wèn)控制 private 一個(gè)派生類(lèi)從一個(gè)基類(lèi)繼承而來(lái),而繼承的方式有多種,可以是私有繼承,也可以是公有繼承,同時(shí)也可以是保護(hù)繼承。那么這個(gè)時(shí)候基類(lèi)的各個(gè)數(shù)據(jù)成員的訪問(wèn)屬性又是怎么樣的呢,我們來(lái)看一下下面這張圖,其展現(xiàn)了以各種方式繼承自基類(lèi)的派生類(lèi)的數(shù)據(jù)成員的屬性。
image-20210209223145289 從這個(gè)表可以清楚地知道基類(lèi)的訪問(wèn)屬性與派生類(lèi)的訪問(wèn)屬性的對(duì)應(yīng)情況。同樣的,我們用一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明這個(gè)知識(shí)點(diǎn):
class ?Father {private : ????int ?money;public : ????void ?it_skill (void ) ???? { ????????cout ?<"The?father's?it?skill" ?<<endl ; ????} ????int ?getMoney (void ) ???? { ????????return ?money; ????} ????void ?setMoney (int ?money) ???? { ????????this ->money?=?money; ????} };這個(gè)是基類(lèi)的數(shù)據(jù)成員以及成員函數(shù),為了更好的說(shuō)明繼承后的數(shù)據(jù)的屬性,我們定義一個(gè)?
son類(lèi),代碼如下所示:
class ?Son ?: ?public ?Father {private : ????int ?toy;public : ????void ?play_game (void ) ???? { ????????cout ?<"play_game()" ?<endl ; ????????int ?m; ????????//money?-=?1;?/*?錯(cuò)誤的代碼?*/ ????????m?=?getMoney(); ????????m--; ????????setMoney(m); ????} };上述定義了兩個(gè)類(lèi),一個(gè)是?
Father類(lèi),一個(gè)是?
Son類(lèi),
Son類(lèi)繼承于?
Father類(lèi),這兩個(gè)類(lèi)用通俗的語(yǔ)言進(jìn)行解釋便是,父親有自己的私房錢(qián),兒子有自己的玩具,父親有一項(xiàng)技能是?
it,兒子呢比較喜歡玩游戲。因?yàn)槭抢^承,所以?xún)鹤宇?lèi)具有父親類(lèi)的相關(guān)屬性,但是,作為兒子是不能夠直接去父親兜里拿錢(qián)的,那會(huì)被揍,但是如果兒子需要錢(qián),可以向父親要。這對(duì)應(yīng)的代碼也就是上述中?
money -= 1,但是這是錯(cuò)誤的,不能直接從父親的兜里拿錢(qián),而剩余的三句代碼的意思也就相當(dāng)于是向父親要錢(qián)。用專(zhuān)業(yè)的話來(lái)講也就是:
派生類(lèi)不能夠訪問(wèn)基類(lèi)的私有成員 ,緊接著是主函數(shù)的代碼:
int ?main (int ?argc,?char ?**argv) { ????Son?s; ????s.it_skill(); ????s.setMoney(10 ); ????cout ?<"The?money?is:" ?<endl; ????s.play_game(); ????return ?0 ; }代碼輸出的結(jié)果如下所示:
image-20210209232507917 protected 還是采用比較通俗的話來(lái)敘述這一知識(shí)點(diǎn),兒子相對(duì)于父親的關(guān)系自然是與其他人有所不同的,比如有一把父親房間門(mén)的鑰匙,對(duì)于兒子來(lái)說(shuō)是可以拿到的,但是對(duì)于外人來(lái)說(shuō),這是不可訪問(wèn)的。那在程序中要如何實(shí)現(xiàn)這么一個(gè)功能呢?這里就要引入?
protected了。代碼如下所示:
class ?Father ?{private : ????int ?money;protected : ????int ?room_key;???/*?增添的?room_key?*/ public : ????void ?it_skill (void ) ???? { ????????cout <<"father's?it?skill" <<endl ; ????} ????int ?getMoney (void ) ???? { ????????return ?money; ????} ????void ?setMoney (int ?money) ???? { ????????this ->money?=?money; ????} };我們可以看到在?
Father類(lèi)中,增添了一項(xiàng)就是?
protected修飾的?
room_key,緊接著我們來(lái)看
Son類(lèi)的代碼:
class ?Son ?: ?public ?Father?{private : ????int ?toy;public : ????void ?play_game (void ) ???? { ????????int ?m; ????????cout <<"son?paly?game" <<endl ; ????????m?=?getMoney(); ????????m--; ????????setMoney(m); ????????/*?外人不能拿父親的房間鑰匙 ?????????*?兒子可以 ?????????*/ ????????room_key?=?1 ;? ????} };我們看到,這個(gè)時(shí)候,是可以在?
Son類(lèi)里面直接操作使用?
protected修飾的?
room_key的。在這里總結(jié)一下就是:
派生類(lèi)可以直接訪問(wèn)到基類(lèi)用 protected 修飾的數(shù)據(jù)成員 。接下來(lái),我們繼續(xù)看主函數(shù)的代碼:
int ?main (int ?argc,?char ?**argv) { ????Son?s; ????s.setMoney(10 ); ????cout ?<endl; ????s.it_skill(); ????s.play_game();?? ????//s.room_key?=?1; ????return ?0 ; }通過(guò)上述代碼可以看到?
s.room_key = 1這條語(yǔ)句被注釋了,這條語(yǔ)句是錯(cuò)誤的,雖然基類(lèi)使用了?
protected修飾了?
room_key,但是在主函數(shù)中,仍然是不能夠直接訪問(wèn)?
room_key的。
調(diào)整訪問(wèn)控制 依舊采用比較通俗的話來(lái)闡述,如果兒子從父親那里繼承了一些東西,那這個(gè)時(shí)候,繼承得到的這些東西的處理權(quán)就全在兒子了。在程序里面也是同樣的道理,我們?cè)谏鲜龃a的基礎(chǔ)上進(jìn)行更改,
Father類(lèi)不變,改變?
Son類(lèi)。代碼如下所示:
class ?Son ?: ?public ?Father?{private : ????int ?toy;public : ????using ?Father::room_key; ????void ?play_game (void ) ???? { ????????int ?m; ????????cout <<"son?paly?game" <<endl ; ????????m?=?getMoney(); ????????m--; ????????setMoney(m); ????????room_key?=?1 ;? ????} };上述代碼中,我們可以看到在?
public的作用域內(nèi),我們使用?
using Father::room_key將?
room_key的屬性更改為?
public,做了這樣的更改之后,我們就可以在主函數(shù)里直接訪問(wèn)?
room_key了。代碼如下所示:
int ?main (int ?argc,?char ?**argv) { ????Son?s; ????s.setMoney(10 ); ????cout ?<endl; ????s.it_skill(); ????s.play_game(); ????s.room_key?=?1 ; ????return ?0 ; }上述代碼是可以運(yùn)行的,也說(shuō)明這種方式是可行的。但是如果想要將?
money的屬性更改為?
public,也就是增加如下所示的代碼:
class ?Son ?: ?public ?Father?{private : ????int ?toy;public : ????using ?Father::room_key; ????using ?Father::money; ????void ?play_game (void ) ???? { ????????int ?m; ????????cout <<"son?paly?game" <<endl ; ????????m?=?getMoney(); ????????m--; ????????setMoney(m); ????????room_key?=?1 ;? ????} };那么編譯將不會(huì)通過(guò),錯(cuò)誤信息如下所示:
image-20210210001456319 說(shuō)明這種方法是不可行的,這是為什么呢?是因?yàn)閷?duì)于?
Son來(lái)說(shuō),
money本身就是它不能訪問(wèn)到的數(shù)據(jù),那么自然也就不能夠?qū)ζ鋵傩赃M(jìn)行更改了。換句更加專(zhuān)業(yè)的話來(lái)敘述也就是:
在調(diào)整訪問(wèn)控制的時(shí)候,只有類(lèi)本身能夠訪問(wèn)到的數(shù)據(jù)才能調(diào)整它的訪問(wèn)控制,如果其本身對(duì)于這個(gè)類(lèi)就是不能夠訪問(wèn)的,那么也就無(wú)法對(duì)其進(jìn)行更改 。那上述可以說(shuō)是提升訪問(wèn)控制,同樣的,也可以降低訪問(wèn)控制,比如說(shuō)上述的?
it_skill,如果不想把這個(gè)屬性繼續(xù)繼承下去或者說(shuō)不讓外部能夠訪問(wèn)到它,那么也可以降低它的訪問(wèn)控制,降低的方法跟提升的方法是一樣的,只需要在?
private中加上一句代碼就可以,加了的代碼如下所示:
class ?Son ?: ?public ?Father {private : ????int ?toy; ????using ?Father::it_skill;public : ????/*?省略?*/ };因此,只要對(duì)于派生類(lèi)能夠看到的數(shù)據(jù)成員或者成員函數(shù),它都能夠提高或者降低它的訪問(wèn)控制。
三種不同繼承方式的差異 在上述的內(nèi)容中,我們提到了派生類(lèi)在繼承基類(lèi)的時(shí)候,存在不同的繼承方式,不同的繼承方式對(duì)數(shù)據(jù)成員的使用以及其成員函數(shù)的調(diào)用存在不同的影響,下面分別是三種不同的繼承方式:
public和?
private以及
protected,代碼如下所示:
/*?以?public?方式繼承?*/ class ?Son_pub ?: ?public ?Father?{private : ????int ?toy;public : ????void ?play_game (void ) ???? { ????????int ?m; ????????cout <<"son?play?game" <<endl ; ????????m?=?getMoney(); ????????m--; ????????setMoney(m); ????????room_key?=?1 ;? ????} };/*?以?private?方式繼承?*/ class ?Son_pri ?: ?private ?Father?{private : ????int ?toy;public : ????void ?play_game (void ) ???? { ????????int ?m; ????????cout <<"son?play?game" <<endl ; ????????m?=?getMoney(); ????????m--; ????????setMoney(m); ????????room_key?=?1 ;? ????} };/*?以?protected?方式繼承?*/ class ?Son_pro ?: ?protected ?Father?{private : ????int ?toy;public : ????void ?play_game (void ) ???? { ????????int ?m; ????????cout <<"son?play?game" <<endl ; ????????m?=?getMoney(); ????????m--; ????????setMoney(m); ????????room_key?=?1 ;? ????} };上述代碼就是以三種不同方式從?
Father類(lèi)得到的?
Son類(lèi),每一種繼承方式存在什么不同呢,我們通過(guò)主函數(shù)來(lái)說(shuō)明這個(gè)問(wèn)題:
int ?main (int ?argc,?char ?**argv) { ????Son_pub?s_pub; ????Son_pro?s_pro; ????Son_pri?s_pri; ????s_pub.play_game(); ????s_pro.play_game(); ????s_pri.play_game(); ????s_pub.it_skill(); ????//s_pro.it_skill();??//?error ????//s_pri.it_skill();??//?error ????return ?0 ; }通過(guò)上述代碼,并對(duì)照上述那種表,我們可以知道,無(wú)論是何種繼承方式,派生類(lèi)內(nèi)部
public的成員函數(shù)都是可以使用的,而對(duì)于從基類(lèi)繼承得到的成員函數(shù),如果是以?
protected和
private方式來(lái)繼承的話,那么是不能夠在主函數(shù)進(jìn)行調(diào)用的,因此上述代碼中注釋掉的兩句后面表明了錯(cuò)誤。上述的代碼所展示的是一層的繼承,我們?cè)诶^承得到的派生類(lèi)?
Son的基礎(chǔ)上繼續(xù)繼承得到?
Grandson,首先我們先在?
Father類(lèi)里新增加一個(gè)
public的數(shù)據(jù)成員,增加的代碼如下所示:
class ?Father {private : ????int ?money;protected : ????int ?room_key;public : ????int ?address; ????/*其余不改動(dòng),省略*/ };增加了上述
Father類(lèi)的代碼之后,我們來(lái)看?
Grandson_pub類(lèi)的代碼:
class ?Grandson_pub ?: ?public ?Son_pub {public : ????void ?test (void ) ???? { ????????room_key?=?1 ;?/*?room_key?is?protected?*/ ????????address?=?2 ;??/*?address?is?public?*/ ????} };上述代碼中,
Grandson_pub是以?
public的方式從?
Son_pub繼承而來(lái),
room_key在?
Father類(lèi)是?
protected,在?
Son_pub類(lèi)也是?
protected,那么在這里也是?
protected,而對(duì)于?
address來(lái)說(shuō),它在?
Father類(lèi)里是?
public,在?
Son_pub里也是?
public,在這里也是?
public,所以在這里都能夠訪問(wèn)到。緊接著來(lái)看,
Grandson_pro類(lèi)的代碼:
class ?Grandson_pro ?: ?public ?Son_pro {public : ????void ?test (void ) ???? { ????????room_key?=?1 ;??/*?room_key?is?protected?*/ ????????address?=?2 ;???/*?address?is?protected?*/ ????} };上述中,
Grandson_pro是以?
public的方式從?
Son_pro中繼承得到的,以剛剛那種分析的思路我們能夠分析得出?
room_key當(dāng)前是?
protected以及?
address是?
protected,那么當(dāng)前的數(shù)據(jù)成員在這也就是都能夠訪問(wèn)的了。繼續(xù)來(lái)看
Grandson_pri類(lèi)的代碼,代碼如下所示:
class ?Grandson_pri ?: ?public ?Son_pri {public : ????void ?test (void ) ???? { ????????//room_key?=?1;?/*?room_key?is?private?*/ ????????//address?=?2;??/*?address?is?private?*/ ????} };上述中,
Grandson_pri是以?
public的方式從?
Son_pri中繼承得來(lái),同樣按照上述的分析方法,我們能夠分析出?
room_key和?
address都是?
private的,既然是?
private的,那么也就不能夠進(jìn)行訪問(wèn),因此上述代碼中,我們將兩句代碼進(jìn)行了注釋。
小結(jié) 上述就是本次分享的關(guān)于封裝以及繼承的相關(guān)內(nèi)容,主要是關(guān)于繼承之后數(shù)據(jù)成員的訪問(wèn)控制,以及通過(guò)不同的方式進(jìn)行繼承時(shí)的數(shù)據(jù)成員的訪問(wèn)控制。
上述教程所涉及的代碼可以通過(guò)百度云鏈接的方式獲取到,下面是百度云鏈接:鏈接:https://pan.baidu.com/s/18AGYqxkxsEcR4ZW6_Nhevg 提取碼:dlst