類與類之間有三大關(guān)系:繼承(Inheritance)、復(fù)合(Composition)和委托(Delegation)
3.1.1 復(fù)合(Composition)
template <class T, class Sequence = deque <T> >
class queue {
? . . .
protected:
? ? ?Sequence c;
public:
? ? ? bool empty() const { return c.empty(); }
? ? ? size_type size() const? { return s.size(); }
? ? ? reference front() { return c.front(); }
? ? ? reference back() { return c.back(); }
? ? ? void push(const value_type& x) {c.push_back(x);}
? ? ? void pop() { c.pop_front(); }
};
3.1.2(Adapter:)改造
//No:1
template?
class?queue{
...
protected?c;//擁有模塊2
...
};
//No:2
template?
class?queue{
protected:
Itr?strat;//擁有模塊3,sizeof:16
Itr?finish;
T**?map;//指針的指針,4個(gè)字節(jié)
unsigned?int?map_size;//4個(gè)字節(jié)
};
//No:3
template?
struct?Itr{
T*?cur;//sizeof:4*4
T*?first;
T* last;
T**?node;
...
};
3.1.3復(fù)合關(guān)系下的構(gòu)造函數(shù)和析構(gòu)函數(shù):
構(gòu)造由內(nèi)而外:Container::Component(...): Component() {...};
Container的構(gòu)造函數(shù)首先調(diào)用Component的default構(gòu)造然后才執(zhí)行自己
析構(gòu)由外而內(nèi):Container :: ~Container(...) { ... ~Component() }
Container的析構(gòu)函數(shù)首先執(zhí)行自己,然后才調(diào)用Component的析構(gòu)函數(shù)
3.2 委托:兩個(gè)類之間相連
class?String{
public:
String();
~String();
String(const?char*s);
String(const?String&?a);
String?&operator=(const?String&?s);
private:
StringRep*?rep;//等到需要用到StringRep時(shí)才去創(chuàng)建StringRep類
};
class?StringRep{
friend?class?String;
StringRep(const?char*?s);
~StringRep();
int?count;
char*?rep;
}
3.3.1 繼承:
struct?_List_node_base
{
_List_node_base*?_M_next:
_List_node_base*?_M_prev;
};
template
struct?_List_node?:public?_List_node_base
{
_Tp ? _M_data;//它除了擁有自己的東西以外,還擁有基類的兩個(gè)東西
};
3.3.2基類的析構(gòu)函數(shù)必須是virtual,否則會(huì)出現(xiàn)undefined behavior
在繼承的情況下,構(gòu)造由內(nèi)而外:Derived::Derived(...) : Base() {...};
Derived的構(gòu)造函數(shù)首先調(diào)用基類的默認(rèn)構(gòu)造函數(shù),然后才執(zhí)行自己
析構(gòu)由外而內(nèi):Derived的析構(gòu)函數(shù)首先執(zhí)行自己,然后才調(diào)用基類的析構(gòu)函數(shù)
Derived::~Derived(...){... ~Base() };
3.3.3
non-virtual函數(shù):你不希望derived class 重新定義它
virtual函數(shù):你希望derived class重新定義它,且它已有默認(rèn)定義。
pure virtual函數(shù):你希望derived class一定要重新定義它,你對(duì)他沒(méi)有默認(rèn)定義。
3.4?純虛函數(shù):virtual 函數(shù)類型 函數(shù)名(參數(shù)表)=0;
聲明為純虛函數(shù)后,基類中就不再給出函數(shù)的實(shí)現(xiàn)部分,且純虛函數(shù)不具備函數(shù)的功能,不能被調(diào)用。
作用:在基類中為其派生類保留一個(gè)函數(shù)的名字。以便派生類根據(jù)需要對(duì)它進(jìn)行重載
3.5. ?inheritance+Composition關(guān)系下的構(gòu)造和析構(gòu):
派生類中有基類的part,但派生類中又有Component,這時(shí),調(diào)用順序是基類=Component.>派生類
派生類中有基類的part,而基類part中又有Component時(shí),這時(shí)調(diào)用順序?yàn)椋篊omponent>基類>派生類,析構(gòu)函數(shù)正好相反
委托+繼承:
class?Subject{
int?m_value;
vector?m_views;//容器里的類型為Observe*
public:
void?attach(Observe*?obs)
m_views.push_back(obs);
void?set_val(int?value)
{
m_value?=?value;
motify();
}
void?notify()
{
for(int?i=0;i
m_views[i]->update(this,m_value);
}
};
class?Observe{
public:
virtual?void?update(Subject*?sub,int?value)const?=0;
};
委托+繼承:
容器里面的東西一定要放一樣的大小,指針是最優(yōu)選
變量名:partname
#nclude
enum?imageType{LAST,SPOT};//枚舉
class?Image{
public:
virtual?void?draw()=0;
static?Image*?findAndClone(imageType);
protected:
virtual?imageType?return?Type()=0;
virtual?Image*?clone()?=0;//要求子類必須對(duì)其進(jìn)行編譯
static?void?assProtype(Image?*image)//靜態(tài)成員函數(shù)
{
_prototypes[_nextSlot++]
}
private:
static?Image*?__prototypes[10];
static?int?_nextSlot;//class當(dāng)中的靜態(tài)date,一定要在這個(gè)類外做一次定義,分配內(nèi)存
};
Image?*Image::_prototypes[];
int?Image::_nextSlot;
Image?*Image::findAndClone(imageType?type)
{//當(dāng)下面所有的子類把自己的一份原型放上去之后填充的數(shù)組
for(int?i=0;i<_nextSlot;i++)
{
if(_prototypes[i]->()?==type)//找到一個(gè)原型之后,調(diào)用clone(),就做了一個(gè)副本
return?_prototypes[i]->clone;
}
public繼承和is-a之間的等價(jià)關(guān)系聽(tīng)起來(lái)頗為簡(jiǎn)單,但有時(shí)候會(huì)誤導(dǎo)人
企鵝是一種鳥(niǎo),這是對(duì)的;鳥(niǎo)會(huì)飛,這也對(duì)的。但企鵝會(huì)飛嗎?
class Bird{
public:
virtual void fly();//鳥(niǎo)會(huì)飛
...
};
class Penguin:public Bird{//企鵝是一種鳥(niǎo)
...
};
這個(gè)代碼但是是行得通的,但是那不是真的。
上述例子中,有一個(gè)與事實(shí)不符的error。如果謹(jǐn)慎一點(diǎn),應(yīng)該是:有的鳥(niǎo)會(huì)飛,有點(diǎn)鳥(niǎo)不會(huì)飛。來(lái)塑模出較佳的真實(shí)性:
class Bird{
public:
...//沒(méi)有聲明fly()函數(shù)
};
class FlyingBird:public Bird{
public:
? ? ? virtual void fly();//鳥(niǎo)會(huì)飛
? ? ? ?...
};
class Penguin:public Bird{//企鵝是一種鳥(niǎo)
...
};
這樣的繼承體系才能比原先的設(shè)計(jì)更能忠實(shí)反映出真正的意思。
現(xiàn)在,如果非得要求企鵝會(huì)飛,那編譯器會(huì)不滿:
Penguin p;
p.fly();//錯(cuò)誤
一個(gè)好的接口可以防止無(wú)效的代碼通過(guò)編譯,因此應(yīng)該采取“在編譯期拒絕企鵝飛行”的設(shè)計(jì),而不是“只在運(yùn)行期間才能偵測(cè)它們”的設(shè)計(jì)。
所以,is-a并不是唯一存在于類之間的關(guān)系。