Week3 notes
A.面向對象編程茸苇,面向對象設計
composition渡八,復合表示has-a
template>
class queue{
…
protected:
Sequencec; //底層容器
Public:
//以下玩完全利用c的操作函數(shù)完成
boolempty() const {return c.empty();}
size_typesize() const {return c.size();}
referencefront() {return c.front();}
referenceback() {return c.back();}
//
void push(constvalue_type& x) {c.push_back(x);}
void pop(){c.pop_front();}
};
a擁有b就叫composition灶体,以上是一個特例环形,a擁有b囱桨,a所有的功能都用b來實現(xiàn)偏化,但現(xiàn)實生活中確實有這種東西,deque的意思是兩端都可以進出抡秆。所以deque得功能比queue強大奕巍。這里做的是改裝一下,比如最后的pop方法儒士,換了一個面貌出現(xiàn)的止,說不定deque有一百個功能,但現(xiàn)只包含了6個功能着撩,而且名字可能變了诅福,這是一種設計模式,叫做adaptor拖叙。變壓器氓润,改造,適配薯鳍,現(xiàn)在手上有一個東西完全滿足要用的功能咖气,只是可能接口不同,名字不同挖滤,所以就改造一下崩溪,這里queue就是adaptor.
從內存的角度來理解。
40
Template
Class queue{
Protected:
Dequec;
}
16*2+4+4
template
class deque{
protected:
Itrstart;
Itr finish;
T** map;
Unsigned intmap_size;
}
4*4
template
struct Itr{
T* cur;
T*
T*
T*
}
復合關系下的構造和析構:
構造由內而外斩松,container的構造函數(shù)首先調用component的default構造函數(shù)伶唯,然后才執(zhí)行自己。
Container::container(…): component(){…};
析構由外而內惧盹,container的析構函數(shù)首先執(zhí)行自己乳幸,再調用component的析構函數(shù)。
Container::~container(…) {…~component()};
這些部分編譯器自己會加上去钧椰,形成合理粹断。構造函數(shù)是默認的這一個,如果這一個不符合的話演侯,就要我們自己寫姿染,自己調用內部的構造函數(shù),輸入都要自己寫,但是析構函數(shù)只有一個所以不需要悬赏。
I’?
Delegation委托狡汉,composition byreference.ZX
String.hpp
Class StringRep;
Class String{
Public:
String();
String(constchar* s);
String(constString& s);
Stringoperator=(const String& s);
~String();
private:
StringRep*rep; //pimpl
};
#include “String.hpp”
namespace{
class stringRep{
friend class String;
StringRep(constchar* s);
~StringRep();
intcount;
char*rep;
}
};
兩個類之間用指針相連就叫委托,如果有了一個外部的就有一個內部闽颇,就叫composition盾戴,現(xiàn)在用指針相連,只有在要用到右邊的時候才用到兵多,叫委托尖啡,也叫composition by reference,具體的實現(xiàn)都在右邊做,當左邊要用到的時候調用右邊的服務剩膘,這種寫法非常有名衅斩,pointer to implementation. Handle/body為什么這么有名呢?因為我們如果把類都寫成這樣的話怠褐,左手邊都不需要換畏梆,字符串如果要怎么變這個指針可以指向不同的實現(xiàn)類,右邊怎么變動都不影響左邊奈懒,也就不影響客戶端奠涌,這個手法也叫編譯防火墻,左邊都不需要管右邊磷杏。
但用指針三個人共享同一個hello要注意abc互相不知道他們引用同一個溜畅,當a改變的時候要單獨給你一份改,叫copy on write.
Inheritance繼承极祸,表示is-a
Struct _List_node_base
{
_list_node_base*Mnext;
Listnodebase*_M_prev;
};
template
struct _List_node
:public_List_node_base
{
_Tp_M_data;
}
c++有三種繼承慈格,使用public繼承就是is-a,如果你用public繼承但兩個類的關系不是is-a贿肩,將來有可能出錯峦椰。
繼承關系下的構造和析構龄寞。Derived派生類汰规。從內存的角度來看子類的對象里頭有一個父類的base part,base class的dtor必須是virtual的物邑,否則會出現(xiàn)undefined behavior
構造要由內而外溜哮,
derived的構造函數(shù)首先調用base的default構造函數(shù),然后才執(zhí)行自己色解。
Derivevd::derived(…): base(){…};
析構由外而內
derived的析構函數(shù)首先執(zhí)行自己茂嗓,然后才調用base的析構函數(shù)。
Derived::~derived(…) {…~base()};
繼承要搭配虛函數(shù)virtual function
B.虛函數(shù)與多態(tài)
虛函數(shù)與繼承
當我們使用繼承的時候要搭配虛函數(shù)科阎,非虛函數(shù)non-virtual function是你不希望derived class重新定義(override,復寫)他述吸。
虛函數(shù)是你希望derived class重新定義(override)它已有的默認定義。Override一定被用在虛函數(shù)被重新定義。
Pure virtual函數(shù)是你希望derived class一定要重新定義它蝌矛,你對他沒有默認定義道批。和虛函數(shù)的區(qū)別是你根本沒有定義。
Class Shape{
Public:
Virtualvoid draw() const = 0;//pure virtual
Virtualvoid error(const std::string& msg);//impure virtual
IntobjectID() const;//non-virtual
…
}
class Rectangle: public Shape{…};
class Ellipse: public Shape {…};
CDocument::
OnFileOpen(){
…
Serialize()
…
}
讀的動作是serialize()
我們寫我們自己的子類
class CMyDoc:
publicCDocument{
virtualSeriallize() {…}
}
main(){
CmyDocmyDoc;
myDoc.OnFileOpen();
}
通過子類的對象調用父類的函數(shù)入撒。函數(shù)的全名是CDocument::OnFileOpen(&myDoc);
23個設計模式之一Template
Method隆豹,模板方法,將一些函數(shù)延緩寫出來茅逮,我先幫你想好了你要寫一個應用程序你要有哪些功能璃赡,很多功能都是相同的,我先幫你預設好献雅,具體的部分留到你自己的子類中去重構他碉考。這里的CDocument中的OnFileOpen是應用框架,Application Framework挺身,十多年前MFC Microsoft Foundation classes
繼承和復合關系下的構造和析構
如果子類繼承父類之外又有一個component,那哪個構造函數(shù)先被調用呢豆励?
如果父類中有一個component的話又是怎么樣呢?
1父類瞒渠,component,子類
委托加繼承關系
Office軟件中可以開多個窗口看同一個東西良蒸。或者是同一份數(shù)據(jù)可以用三種不同的形式觀察伍玖。要想有這種功能嫩痰,有兩個CLASS一種是存儲,一種是表現(xiàn)窍箍。
Class Subject{
Intm_value;
Vectorm_views;
Public:
Voidattach(Observer* obs){
M_views.push_back(obs);
}
void set_val(intvalue){
m_value = value;
notify();
}
void notify(){
for(int I = 0; i< m_value.size();i++)
m_views[i]->update(this, m_value);
}
};
class Observer{
public:
virtualvoid update(Subject*sub, int value) = 0;
};
左邊是有一個delegation的關系串纺,左邊要有注冊和注銷的功能。Attach實現(xiàn)注冊功能椰棘。
C.委托相關設計
委托加繼承
Composite
現(xiàn)在要寫一個file system纺棺,有目錄,有文件邪狞,目錄里面可以放文件祷蝌,目錄還可以放到其他目錄里。window system,大窗口里面有小窗口帆卓。那應該使用哪些class巨朦,應該使用什么將他們聯(lián)系起來。
目錄系統(tǒng)剑令。
Primitive糊啡,composite可以放左邊的primitive,也可以放自己吁津,如果左邊和右邊寫一個父類棚蓄,這樣兩邊都是is-a component,所以就可以寫成c:vector,不能放對象,要放指針,右邊這個東西是一個組合物梭依,所以他應該具有一個函數(shù)add(e:component*),因為它又可以加左邊的東西挣柬,,也可以加右邊的東西睛挚,這樣兩個東西都可以接受邪蛔。發(fā)現(xiàn)有很多解法都是要用到兩把武器。這種解法叫做composite是23個設計模式中的一個扎狱。
Class primitive: public Component{
Public:
Primitive(intval): Component(val) {}
};
class Component{
intvalue;
public:
Component(intval) {value = val;}
Virtualvoid add(component*) {}
};
class Composite: public component{
vectorc;
public:
composite(intval): component(val) {}
voidadd(component* elem) {
c.puch_back(elem);
}
…
};
prototype
我要創(chuàng)建未來
LandSatImage是一個子類侧到,都有一個靜態(tài)的自己,很久以前寫好的框架要能看得到后來寫的東西淤击,-LandSatImage(),負的代表private匠抗,#代表Protected,我們故意把構造函數(shù)設為私有,那在創(chuàng)建的時候私有的構造函數(shù)可以被調用起來嗎污抬?可以汞贸,因為是自己人,不是外界在調用印机,我們就借用這個私有的構造函數(shù)矢腻,addPrototype(this).而且掛上去在父類中看得到。父類Image中射赛,有addPrototype(p:Image*):void而且所有的子類都應該有一個函數(shù)clone():Image*,做的事情是return
new LandSatImage.通過原型這個對象可以調用clone這個函數(shù)多柑,如果沒有這個原型的話。
D.復合楣责,繼承關系下的構造和析構
繼承關系下的構造和析構
復合關系下的構造和析構
繼承加上復合關系下的構造和析構
我們要談的是class和class之間的關系竣灌,三種關系。當發(fā)生繼承時秆麸,子類對象里頭有一個父類的成分初嘹。豬是一種哺乳動物,豬里頭就應該有哺乳動物的成分沮趣,哺乳動物應該有動物的成分屯烦。由于有這樣的關系,當我們在探討構造和析構的時候兔毒,我們要注意由內而外漫贞,析構函數(shù)要先執(zhí)行自己,再調用父類的析構育叁。
繼承和復合關系下的構造和析構,子類的構造函數(shù)首先調用父類的default構造函數(shù)芍殖,然后調用component的default構造函數(shù)豪嗽,最后才執(zhí)行自己。
析構由外而內,子類的析構函數(shù)首先執(zhí)行自己龟梦,然后調用component的析構函數(shù)隐锭,最后調用base的析構函數(shù)。
本次作業(yè)要求構造十個隨機矩形和隨機十個圓并根據(jù)他們的面積進行刪選计贰,遇到的問題有一開始思考如何將兩個類的對象放在一個數(shù)組里钦睡,很普通的問題,說明肯定已經(jīng)有完美的解決方案躁倒,多態(tài)的使用荞怒,即使用基類指針指向子類對象,這時一定要注意要在子類中使用的方法一般都要在基類中使用虛函數(shù)或者純虛函數(shù)先寫出來秧秉,再在下面的子類中進行重載褐桌。包含有純虛函數(shù)的類叫做虛類,那什么時候我們需要構建一個虛類呢象迎?當類是一個抽象概念的時候荧嵌,比如這個題目中形狀這個類,我們就要構建它為虛函數(shù)砾淌,因為沒有一個對象是一個形狀啦撮,我們也不會將這個類實例化。具體的做法是shape** a = new shape* [20],這樣就構建了一個指針數(shù)組汪厨,且數(shù)組也使用指針表示逻族,第二個遇到的問題是在刪選出合適的對象后,我一開始想要調用拷貝賦值函數(shù)骄崩,發(fā)現(xiàn)很麻煩聘鳞,實際上可以直接拷貝指針,省去很多問題要拂。然后不需要建立兩個數(shù)組抠璃,可以用快慢指針的方法將符合要求的一個個拷貝到當前數(shù)組,并將不符合的刪除脱惰,注意在刪除的時候要將指針置為空指針搏嗡,在刪除數(shù)組的時候要用delete[]。