類與類之間有三大關系:繼承(Inheritance)扣墩、復合(Composition)和委托(Delegation)
3.1.1 復合(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個字節(jié)
unsigned?int?map_size;//4個字節(jié)
};
//No:3
template?
struct?Itr{
T*?cur;//sizeof:4*4
T*?first;
T* last;
T**?node;
...
};
3.1.3復合關系下的構造函數(shù)和析構函數(shù):
構造由內而外:Container::Component(...): Component() {...};
Container的構造函數(shù)首先調用Component的default構造然后才執(zhí)行自己
析構由外而內:Container :: ~Container(...) { ... ~Component() }
Container的析構函數(shù)首先執(zhí)行自己顷牌,然后才調用Component的析構函數(shù)
3.2 委托:兩個類之間相連
class?String{
public:
String();
~String();
String(const?char*s);
String(const?String&?a);
String?&operator=(const?String&?s);
private:
StringRep*?rep;//等到需要用到StringRep時才去創(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;//它除了擁有自己的東西以外,還擁有基類的兩個東西
};
3.3.2基類的析構函數(shù)必須是virtual吟温,否則會出現(xiàn)undefined behavior
在繼承的情況下翎碑,構造由內而外:Derived::Derived(...) : Base() {...};
Derived的構造函數(shù)首先調用基類的默認構造函數(shù)槽唾,然后才執(zhí)行自己
析構由外而內:Derived的析構函數(shù)首先執(zhí)行自己,然后才調用基類的析構函數(shù)
Derived::~Derived(...){... ~Base() }光涂;
3.3.3
non-virtual函數(shù):你不希望derived class 重新定義它
virtual函數(shù):你希望derived class重新定義它庞萍,且它已有默認定義。
pure virtual函數(shù):你希望derived class一定要重新定義它忘闻,你對他沒有默認定義钝计。
3.4?純虛函數(shù):virtual 函數(shù)類型 函數(shù)名(參數(shù)表)=0;
聲明為純虛函數(shù)后齐佳,基類中就不再給出函數(shù)的實現(xiàn)部分私恬,且純虛函數(shù)不具備函數(shù)的功能,不能被調用炼吴。
作用:在基類中為其派生類保留一個函數(shù)的名字本鸣。以便派生類根據(jù)需要對它進行重載
3.5. ?inheritance+Composition關系下的構造和析構:
派生類中有基類的part,但派生類中又有Component,這時硅蹦,調用順序是基類=Component.>派生類
派生類中有基類的part荣德,而基類part中又有Component時,這時調用順序為:Component>基類>派生類童芹,析構函數(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;//要求子類必須對其進行編譯
static?void?assProtype(Image?*image)//靜態(tài)成員函數(shù)
{
_prototypes[_nextSlot++]
}
private:
static?Image*?__prototypes[10];
static?int?_nextSlot;//class當中的靜態(tài)date,一定要在這個類外做一次定義辐脖,分配內存
};
Image?*Image::_prototypes[];
int?Image::_nextSlot;
Image?*Image::findAndClone(imageType?type)
{//當下面所有的子類把自己的一份原型放上去之后填充的數(shù)組
for(int?i=0;i<_nextSlot;i++)
{
if(_prototypes[i]->()?==type)//找到一個原型之后饲宛,調用clone(),就做了一個副本
return?_prototypes[i]->clone;
}
public繼承和is-a之間的等價關系聽起來頗為簡單皆愉,但有時候會誤導人
企鵝是一種鳥嗜价,這是對的;鳥會飛幕庐,這也對的久锥。但企鵝會飛嗎?
class Bird{
public:
virtual void fly();//鳥會飛
...
};
class Penguin:public Bird{//企鵝是一種鳥
...
};
這個代碼但是是行得通的异剥,但是那不是真的瑟由。
上述例子中,有一個與事實不符的error冤寿。如果謹慎一點歹苦,應該是:有的鳥會飛,有點鳥不會飛督怜。來塑模出較佳的真實性:
class Bird{
public:
...//沒有聲明fly()函數(shù)
};
class FlyingBird:public Bird{
public:
? ? ? virtual void fly();//鳥會飛
? ? ? ?...
};
class Penguin:public Bird{//企鵝是一種鳥
...
};
這樣的繼承體系才能比原先的設計更能忠實反映出真正的意思殴瘦。
現(xiàn)在,如果非得要求企鵝會飛号杠,那編譯器會不滿:
Penguin p蚪腋;
p.fly();//錯誤
一個好的接口可以防止無效的代碼通過編譯丰歌,因此應該采取“在編譯期拒絕企鵝飛行”的設計,而不是“只在運行期間才能偵測它們”的設計屉凯。
所以立帖,is-a并不是唯一存在于類之間的關系。