組合與繼承
Composition(復(fù)合)
??????? 一個類包含另一個類(has-a)卵牍,可以通過Adapter改造一個類,即一個對象為另一個對象的子對象(成員)铣揉。
?????? ?在構(gòu)造時由內(nèi)而外窜骄,先調(diào)用內(nèi)部類的構(gòu)造函數(shù),在構(gòu)造自己奔浅;在析構(gòu)時馆纳,先析構(gòu)自己再析構(gòu)內(nèi)部類。
Delegation(委托)
?????? ?一個類里面有一個指針指向另一個類汹桦,當(dāng)前類委托另一個類實現(xiàn)各種操作鲁驶。可以多個對象里面的指針指向同一個委托對象舞骆。兩個類的生命周期不一致钥弯。
? ? ? ? Handle/Body模式:將類的接口和類的實現(xiàn)相互分開,對實現(xiàn)類的修改不會影響對外的使用督禽。其相比繼承而言有更大的靈活度脆霎。
Inheritance(繼承)
??? class class_name2:?access_specifiers?class_name1
??? {
??? }
??????? class1完全包含class2的內(nèi)容,calss1為基類狈惫,class2為派生類睛蛛。其構(gòu)造與析構(gòu)順序和復(fù)合關(guān)系一樣,不同的是對于編譯器來說class2對象本身就是一個class1對象。class1的引用和指針完全可以綁定到class2對象上忆肾。即
class2 cl2荸频;
class1 &cl1=cl2;
class1 *p=&cl2客冈;
??????? 完全是合法的旭从。但是cl1還是一個class1的引用,p還是一個class1的指針郊酒,所以需要一個class2類型的指針和引用的地方遇绞,不能用p和cl1來代替。
虛函數(shù)與多態(tài)
??????? 基類的析構(gòu)函數(shù)必須為virtual(虛函數(shù))燎窘。
??????? non-virtual函數(shù):不能被子類重新定義(override)摹闽;
??????? virtual函數(shù):基類已經(jīng)默認(rèn)定義了,但是希望子類重新定義褐健;
??????? pure virtual函數(shù):沒有默認(rèn)定義付鹿,子類必須重新定義;對于含有純虛函數(shù)的類成為抽象類蚜迅,不能產(chǎn)生實例舵匾,只能被派生類繼承,且如果派生類沒有重新定義的話谁不,派生類也為一個抽象類坐梯。
繼承+復(fù)合關(guān)系下的構(gòu)造與析構(gòu)
?????? 構(gòu)造時先構(gòu)造Component,然后構(gòu)造基類Base刹帕,最后才構(gòu)造Derived吵血。析構(gòu)時先調(diào)用Derived的析構(gòu)函數(shù),然后析構(gòu)Base最后進(jìn)行Component的析構(gòu)偷溺。
經(jīng)測驗Base的構(gòu)造函數(shù)會先于Component的構(gòu)造函數(shù)調(diào)用蹋辅;析構(gòu)時Component的析構(gòu)函數(shù)先于Base的析構(gòu)函數(shù)調(diào)用。
委托+繼承(composite)
???
??????? 為了讓composite中的容器能夠放入primitive和composite兩種不同的類挫掏,那么可以讓這兩個類有同一個基類(繼承)侦另。然后基類的指針(委托)可以指向任何一個派生類。
??????? 基類不知道會派生出哪些派生類尉共,而有需要知道派生出的類的名稱褒傅。在寫出派生類之后,派生類創(chuàng)建一個自己這種靜態(tài)對象(LSAT),然后把自己的靜態(tài)對象添加到基類的addPrototype里面的指針中袄友。然后需要創(chuàng)建某一個派生類對象時通過相應(yīng)的靜態(tài)對象中的clone函數(shù)復(fù)制一個當(dāng)前對象樊卓,然后為復(fù)制出的對象的變量賦值完成一個對象的創(chuàng)建。
??????? 參考資料sourcemaking.com/design_patterns/prototype杠河;該網(wǎng)站列出了一些參考示例,使用prototype的目的,與存在的問題券敌。
作業(yè)過程中面臨的問題與解決方案
???????? 在本次作業(yè)中有兩套不同的解決方案唾戚,一種是按照普通的繼承與復(fù)合關(guān)系完成的;另一種是通過prototype設(shè)計模式進(jìn)行作業(yè)(未完成)待诅。
??????? 在普通的繼承關(guān)系中存在以下問題:
??????? 1. 作業(yè)中要求通過一個傳統(tǒng)數(shù)組保存兩種類型的對象叹坦,但是對于數(shù)組的描述中明確表示了數(shù)組是相同類型的數(shù)據(jù)按照一定的數(shù)序排列。
???????? 解決方案是卑雁,由于兩中類都是同一個類Shape的派生類募书,而Shape形指針又完全可以指向Shpae及其派生類的對象,所以可以創(chuàng)建一個Shape形指針數(shù)組测蹲,以達(dá)到題目要求莹捡。
??????? 2. 由于數(shù)組中是保存的Shape形指針,當(dāng)指針解引用時也被編譯器當(dāng)作了一個Shape形的對象扣甲。在輸出流操作符<<重載時篮赢,為了使std::cout滿足操作習(xí)慣不能采用成員函數(shù)形式重載。而在普通函數(shù)重載時就要為Circle與Rectangle各自進(jìn)行一個重載琉挖,參數(shù)如下:
std::ostream& operator <<(std::ostream &os, Rectangle const &re)启泣;
std::ostream& operator <<(std::ostream &os, Circle const &ce);
可以看到區(qū)別它們之間不同的為形參列表示辈,但是我的對象是由Shape指針保存的寥茫,不能有效區(qū)分,導(dǎo)致不能調(diào)用相應(yīng)的流操作符矾麻。
??????? 解決方案為:可以采用以下兩種方案纱耻,將expression轉(zhuǎn)換為type_id對象的指針或引用
? dynamic_cast<type-id>(expression)
? static_cast < type-id > ( expression )
在進(jìn)行由派生類道基類的轉(zhuǎn)化時,它們倆沒什么區(qū)別射富。但是當(dāng)由基類向派生類轉(zhuǎn)化時膝迎,dynamic_cast具有類型檢查,比如expression確實指向一個派生類對象時胰耗,沒問題返回一個派生類的指針限次,當(dāng)expression沒有指向type-id類時返回一個空指針,可用于判斷柴灯。而static_cast由于沒有類型檢查所以下行轉(zhuǎn)換時時不安全的卖漫。
??????? 3. 對于**ptr指針作為函數(shù)形參時const的使用如下:
? ? ? ? ? const MyStructure *? ? ? *ppMyStruct;
??????? // ptr --> ptr --> const MyStructure
??????? MyStructure *const *ppMyStruct;
??????? // ptr --> const ptr --> MyStructure
??????? MyStructure *? ? ? *const ppMyStruct;
?????? ?// const ptr --> ptr --> MyStructure
??????? 如上,如果ptr所指的指針與指針?biāo)傅闹颠€有ptr本身都不會在函數(shù)中改變的話赠群,可以采用 const *const *const ptr羊始;這種方式。沒有找到對這種用法的相關(guān)建議是否應(yīng)該少用之類的查描,但是這種用法確實對于理解有一定的困難突委。
在使用prototype設(shè)計模式進(jìn)行作業(yè)
? ? ? ? 1. 這種設(shè)計模式強(qiáng)調(diào)我們在運行時去創(chuàng)建一個對象時柏卤,不需要完全的重新初始化對象,并且不需要知道對象屬于哪一個派生類也能夠創(chuàng)建出相應(yīng)的對象匀油。但是如果兩個派生類所需的構(gòu)造函數(shù)形參列表不同缘缚,就不能通過*shape=class_name()來改變一個對象里面的值,和上面一樣也要通過類型的強(qiáng)制轉(zhuǎn)換“dynamic_cast(expression)”敌蚜。而像示例代碼這樣添加一個draw()純虛函數(shù)桥滨,用以改變對象的值,但是純虛函數(shù)在復(fù)寫的時候又要求形參列表要和基類一樣弛车,而circle和rectangle所需的參數(shù)數(shù)量肯定是不一樣的齐媒,最后只有采用笨辦法dynamic_cast改變值。但是網(wǎng)上說用了dynamic_cast就代表類設(shè)計上就有問題纷跛,一個完好的類的設(shè)計是不需要用到dynamic_cast的~~~~
? ? ? ? 2. 這種設(shè)計模式在規(guī)模較小的程序中喻括,代碼復(fù)雜度提升太大,為了實現(xiàn)這個模式而添加的代碼都差不多和普通的一個派生類的所有代碼行數(shù)相當(dāng)忽舟。反而不如普通的直接繼承更方便双妨,也許是我反應(yīng)慢,照著(sourcemaking.com)里面的示例代碼編寫了一個以這種模式為基礎(chǔ)的作業(yè)叮阅,感覺有時候自己都看不懂了~~~~
總結(jié):本章最難的我認(rèn)為就數(shù)設(shè)計模式這部分了刁品,特別是prototype這種,看示例代碼好像很簡單浩姥,但是一到自己寫這種設(shè)計模式的代碼的時候挑随,就完全不知道該寫什么了呢。反而不明不白的寫了好多完全沒有用的代碼勒叠。