面向?qū)ο笤O(shè)計(jì)是一種思想,而C++恰好是一種面向?qū)ο蟮恼Z(yǔ)言,在C++中設(shè)計(jì)類(lèi)一般都會(huì)采用繼承基類(lèi)(父類(lèi)),設(shè)計(jì)派生類(lèi)(子類(lèi)),繼承和動(dòng)態(tài)綁定的結(jié)合就巧妙的實(shí)現(xiàn)了實(shí)際的問(wèn)題。但是如何設(shè)計(jì)出一個(gè)強(qiáng)大的類(lèi)呢?今天在學(xué)習(xí)了純虛函數(shù)以后,我又覺(jué)得分層設(shè)計(jì)的思想真的是一個(gè)非常棒的設(shè)計(jì)思想。
首先說(shuō)明一下我只是一個(gè)初學(xué)者,寫(xiě)出來(lái)的東西可能會(huì)有錯(cuò)誤,說(shuō)實(shí)在的沒(méi)寫(xiě)過(guò)多少代碼,但是我認(rèn)為寫(xiě)代碼是一個(gè)熟練的過(guò)程,一個(gè)完成思想的過(guò)程。只有有了思想,才能完成好的設(shè)計(jì),不斷的思考,不斷的總結(jié)才能學(xué)到新學(xué)到的東西,才能達(dá)到更高的目標(biāo)。
在C++中虛函數(shù)是指將一個(gè)類(lèi)中的虛函數(shù)后面加上=0,就說(shuō)明該虛函數(shù)為純虛函數(shù)。一般該函數(shù)設(shè)置為純虛函數(shù),那么該函數(shù)也就沒(méi)有再次定義的必要了,因?yàn)榇嬖诩兲摵瘮?shù)的類(lèi)就是一個(gè)抽象類(lèi),是不能夠創(chuàng)建對(duì)象的,不能創(chuàng)建對(duì)象也就不會(huì)主動(dòng)的調(diào)用該函數(shù),哪怕在動(dòng)態(tài)綁定的情況下也不會(huì),因此不需要為該函數(shù)定義相關(guān)的操作,實(shí)質(zhì)上在此處聲明只是說(shuō)明在該派生類(lèi)中需要重寫(xiě)基類(lèi)的虛函數(shù),至于是否真的復(fù)寫(xiě),不要去關(guān)心。
//存在純虛函數(shù)的類(lèi)為抽象類(lèi)
class AbstructClass:public Base
{
public:
//構(gòu)造函數(shù)
AbstructClass(...):Base(...),...{}
//析構(gòu)函數(shù)
~AbstructClass(){...}
//這就是純虛函數(shù),一般func在基類(lèi)中就為虛函數(shù),因此virtual也可以不寫(xiě)
virtual func(...) const = 0;
//保證派生類(lèi)能夠訪問(wèn)數(shù)據(jù)成員,必須設(shè)置為protected
protected:
//一些數(shù)據(jù)成員定義
...
};
抽象類(lèi)的作用主要是幫助完成實(shí)際派生類(lèi)的設(shè)計(jì),為什么這么說(shuō)呢?如果我們只創(chuàng)建一個(gè)基類(lèi),直接繼承基類(lèi)創(chuàng)建實(shí)際的派生類(lèi),存在很多的問(wèn)題,為什么這么說(shuō)呢?比如說(shuō)我要?jiǎng)?chuàng)建一個(gè)人的類(lèi),我們每一個(gè)人都是一個(gè)人的對(duì)象,在人的基類(lèi)中一般只是包含了人的共性,不可能將某一個(gè)人的特殊定義到類(lèi)中,當(dāng)然為了繼承,肯定也會(huì)創(chuàng)建一系列的虛函數(shù)。如果我們每一個(gè)人都直接從該基類(lèi)派生,人的個(gè)體在世界上有60多億,我們每一個(gè)人實(shí)際上就是一個(gè)派生類(lèi),因?yàn)槊恳粋(gè)人都不同,都有自己獨(dú)特的特性(假設(shè)是一種數(shù)據(jù)對(duì)象),如果要實(shí)現(xiàn)這么多的派生類(lèi)真的是一個(gè)不可想象的,而且我們可以知道很多人(類(lèi))實(shí)際上存在很多的相似性。
這時(shí)我們實(shí)際上就可以采用抽象類(lèi)來(lái)幫忙完成我們的設(shè)計(jì)。抽象類(lèi)是連接在基類(lèi)和實(shí)際派生類(lèi)之間的中間類(lèi),實(shí)際派生類(lèi)的直接基類(lèi)是抽象類(lèi),也就說(shuō)說(shuō)基類(lèi)是實(shí)際派生類(lèi)的間接基類(lèi)。在抽象層中主要完成什么操作呢?抽象層中主要完成對(duì)派生類(lèi)共性數(shù)據(jù)成員的定義,為了方便派生類(lèi)的數(shù)據(jù)訪問(wèn),必須設(shè)置為受保護(hù)訪問(wèn)權(quán)限,創(chuàng)建純虛函數(shù),定義構(gòu)造函數(shù),應(yīng)該在初始化列表中首先創(chuàng)建基類(lèi)對(duì)象,然后才能完成其他成員的初始化,有時(shí)候可能需要復(fù)制控制函數(shù)的實(shí)現(xiàn)。
在實(shí)際的派生類(lèi)設(shè)計(jì)過(guò)程中就不再直接從基類(lèi)繼承,而是從抽象類(lèi)中繼承,因?yàn)槌橄箢?lèi)中增加了一些受保護(hù)成員數(shù)據(jù),且這些數(shù)據(jù)成員時(shí)派生類(lèi)的共性,因此派生類(lèi)中可以很方便的訪問(wèn)。同時(shí)在該派生類(lèi)中就應(yīng)該完成虛函數(shù)的復(fù)寫(xiě)操作,因?yàn)閯?dòng)態(tài)綁定以后會(huì)直接調(diào)用該版本的虛函數(shù)。當(dāng)然有時(shí)候也要完成復(fù)制控制函數(shù)的定義。當(dāng)然可以設(shè)計(jì)很多基于抽象類(lèi)的派生類(lèi)。當(dāng)然在派生類(lèi)中也可以增加自己的數(shù)據(jù)成員。
//實(shí)際派生類(lèi)從抽象類(lèi)中繼承
class ActualClass : public AbstructClass
{
public:
ActualClass(...):AbstructClass(...),...{}
//派生類(lèi)中復(fù)寫(xiě)虛函數(shù)
func()
{...}
private:
//派生類(lèi)的一些數(shù)據(jù)
...
};
基本的思想如下圖所示:
從上面的圖可知,我們可以在實(shí)際的派生類(lèi)與基類(lèi)之間增加一個(gè)中間層,這種實(shí)現(xiàn)方式不僅能夠更好的隱藏?cái)?shù)據(jù),而且比較好的解決了我們上面提到的派生類(lèi)過(guò)實(shí)現(xiàn)過(guò)于復(fù)雜的問(wèn)題。因此我們可以認(rèn)為抽象類(lèi)實(shí)際上就是一個(gè)分層設(shè)計(jì)的方法,也可以認(rèn)為是一個(gè)分成更加精細(xì)子類(lèi)的方式方法,也就是說(shuō)在基類(lèi)的基礎(chǔ)上將對(duì)象分成很多子類(lèi)(抽象類(lèi)),然后在各個(gè)子類(lèi)下設(shè)計(jì)新的派生類(lèi)。比如在圖中的抽象類(lèi)1,抽象類(lèi)2是不同的,是兩種不同的分類(lèi),這候我們給予兩個(gè)抽象類(lèi)的派生類(lèi)當(dāng)然也就存在了差別。這樣實(shí)現(xiàn)的好處能夠避免很多的重復(fù)代碼。
就假設(shè)我們要實(shí)現(xiàn)一個(gè)比較簡(jiǎn)單的校園人類(lèi),假設(shè)已經(jīng)存在了一個(gè)人的基類(lèi)(Base),那么學(xué)校的人存在很多的特征,但是我認(rèn)為主要分成了3大類(lèi),主要是學(xué)生、教師、服務(wù)人員,因此可以再基類(lèi)的基礎(chǔ)上派生出三個(gè)抽象類(lèi),Studtent, Teacher, Service,就如同上面的抽象類(lèi)1,抽象類(lèi)2,抽象類(lèi)3。這時(shí)候設(shè)計(jì)一個(gè)實(shí)際的派生類(lèi)也就減小了很多的冗余。但是我們覺(jué)得還是會(huì)存在很多的相似之處,比如學(xué)生類(lèi)而言,還是可以再分,可以分為男女,這樣分并不是最好的,我們實(shí)際上可以按照專(zhuān)業(yè)分,這時(shí)候又可以再Student的基礎(chǔ)上派生出不同的學(xué)生專(zhuān)業(yè)抽象類(lèi),在各個(gè)專(zhuān)業(yè)下又可以分為博士、研究生、大學(xué)生抽象類(lèi),在這些抽象類(lèi)的基礎(chǔ)上還可以分為男女抽象類(lèi),到這時(shí)就可以直接完成具體每一個(gè)派生類(lèi)的實(shí)現(xiàn)啦,這時(shí)候的直接基類(lèi)就是男女學(xué)生抽象類(lèi),這樣就形成了一個(gè)多層次的分解問(wèn)題,將一個(gè)大的問(wèn)題分解成了很多的子類(lèi),在子類(lèi)的基礎(chǔ)上在分成更細(xì)的子類(lèi),最后到達(dá)一個(gè)精細(xì)的抽象子類(lèi),這時(shí)實(shí)現(xiàn)一個(gè)具體的派生類(lèi)就會(huì)非常的方便。也就減少了很多的冗余代碼,雖然設(shè)計(jì)的類(lèi)更多了,但是實(shí)現(xiàn)的方式會(huì)更加的容易。所以說(shuō)分層設(shè)計(jì)的思想是一個(gè)重要的思想,分層就能將一個(gè)大問(wèn)題逐步喜歡,而在C++中純虛函數(shù)(抽象類(lèi))的運(yùn)用就能夠巧妙的解決這種多層次設(shè)計(jì)問(wèn)題。所以說(shuō)我們的分層設(shè)計(jì)不僅僅只是單一層的,也可以是多層次的。如下圖所示:
因此我們應(yīng)該掌握C++中這種純虛函數(shù)的用法,只有掌握了這種設(shè)計(jì)方法才能實(shí)現(xiàn)更加漂亮的類(lèi)設(shè)計(jì)。當(dāng)然上面只是我的一些遐想。具體的實(shí)現(xiàn)過(guò)程還需要在經(jīng)后的實(shí)踐中練習(xí)。在類(lèi)的設(shè)計(jì)中多增加抽象類(lèi)能夠簡(jiǎn)化類(lèi)的冗余度,使得類(lèi)能更加方便的被繼承。從上面的結(jié)果我們可以將分層設(shè)計(jì)看做一個(gè)樹(shù)形結(jié)構(gòu),基類(lèi)就是樹(shù)的根,而實(shí)際的派生類(lèi)是就是葉,而那些中間的抽象層就是節(jié)點(diǎn)。