弄清編寫的是那種類
第一: 值類。
如:std::vectior,std::pair,模仿的是內建類型。他有以下特徵:
Herb Sutter & Andrei Alexandresuc認為有以下特徵:
1. 有一個公用解構函式,複製建構函式和帶有值語義的賦值。
2. 沒有虛擬函數(包括解構函式)。
3. 是用作具體類,而不是基類。
4. 總是在棧中執行個體化,或者作為另一個類直接包含的成員執行個體化。
Bjarne Stroustrup認為:
代表著相對簡單的概念,帶著支援此概念的一組最基本的操作。他們的介面與實現都有一對一的關係,
都不想作為派生的基類。具體類型不適合放進某個相關類的階層中,每個具體類型都能獨立地理解,極少參考其他類。總之,一個具體類型就是一個內部類型。自然,內部類型也都是具體的。
總體目標:
進可能緊密地與某個特定概念或者實現策略相匹配。
通過線上處理,讓操作能夠儘可能地利用概念及其實現的性質,提供相當於“手工打造”代碼的已耗用時間與空間效率。
對其他類只有最小的依耐性。
能夠獨立地理解和使用。
為了以某個具體類型作為參數,函數就必須把確切的具體類型作為參數類型。這裡並不存在繼承關係,無法利用繼承關係去減少參數類型的特殊性。正因為如此,如果企圖利用具體類型間的相似性,就會涉及到模板通用性程式設計(p672)。
這種類更經常被作為成員或者私用基類,在那些情況下可以有效地利用他們,又不會使其介面和實現與新類地介面和實現混合在一起使用,相互連累。
具體類型是以不修改的方式"重用",就像int一類的內部類型:
class Date_and_time{
private:
Date d;
Time t;
public:
//……
};
這種形式的使用通常很簡單、有效、效率也很高。
最後一個良好的具體類型可以用作另一個易塑造的類型的表示。
class Date3{
public:
/ /公用介面,基本上由虛函數組成
private:
Date d;
};
這就是必要時將某個類(具體或是內部類型)納入某個階層的方式。
第二:基類。
1.有一個公用且虛擬,或者保護而且非虛擬解構函式,和一個非公用複製建構函式和賦值操作符。
2.通過虛擬函數建立借口。
3 .總是動態地在堆中執行個體化為具體衍生類別對象,並通過一個(智能)指標來使用。
Bjarne Stroustrup認為:使用抽象基類的原因有二。
一是淡化實現者與類的使用者之間的聯絡。
二是淡化建立對象的代碼和使用這種代碼之間的聯絡。
因此,最簡單便是引入一個抽象類別:
template<class T>
class set
{
public:
virtual void insert(T*) = 0;
virtual void remove(T*) =0;
virtual int is_member(T*) = 0;
virtual T* first() = 0;
virtual T* next() = 0;
virtual ~set() = 0;
};
這就定義了一個集合的介面,帶有一個內部的對元素迭代的概念。
template<class T> class List_set : public set<T>, private list<T> {
//……
}
template<class T>class vector_set : public set<T>,private vector<T>{
//……
}
對於具體類型,我們需要重新設計實作類別去表達某些共性,使用模板去利用其中的共性。
而在這裡,我們必須設計一個公用介面,但對於實現的那些類而言,除了需要實現介面的功能以外,再沒有別
的其他的共性要求了。
為什麼在我們在可以有抽象類別型的時候還要有具體類型呢?
高效率。
重用:重用庫而不是重寫他們。
多重介面:為許多不同的類使用一個單一公用基類將導致肥大的介面。
通常更好的方式是為服務於新用途的類提供新的介面。
第三:traits類,是攜帶有關類型資訊地模板。
1.只包含typedef和靜態函數。沒有可修改的狀態或者虛擬函數。
2.通常不執行個體化(構造一般被靜止)。
第四:策略類(比如模板),是可插拔行為的片段。
1.可能有也肯能沒有狀態或者虛函數。
2.通常不獨立執行個體化,只能作為基類或是成員。
第五:異常類。
1.有一個公用解構函式和不會失敗的建構函式。
2.有虛函數。通常能實現複製和訪問。
3.從std::exception虛擬派生更好。
第六:結點
帶著派生的觀點去構造類階層與用於抽象類別型的介面、實現觀點很不一樣。
一般情況下,在類階層裡的一個類表示一個具有普遍性的概念,其衍生類別可以看成是它的專門化。
被設計者作為某個階層中一個不可缺少的部分的典型類被稱為結點類。它需要依靠基類的服務去提供一些服務,這就是說需要調整一些基類的成員函數。一個典型的結點類不僅提供了由基類刻畫的介面的一個實現,還常常加入自己的新函數,這樣就成為一個更寬廣的介面。
比如:
class car : public vechicle{
public:
car(int passengers, size_category size, int weight, int fc):
vechicle(passengers, size, weight), fuel_capacity(fc){ }
//覆蓋來自vechicle相關虛函數
void turn (Direction );
//……
/增加car的特殊函數:
virtual void add_fuel (int amount);
};
結點類與抽象類別型最大的不同就在於次,他需要有比較複雜的建構函式。而抽象類別型通常極少有建構函式。
對於car的基本操作通常需要在實現中使用基類vehicle提供操作。此外,car 的使用者也依賴於來自基類的服務。
比如:car依賴於vehicle 。
bool Bridge :: can_cross(const vechicle & r)
{
if(max_weight < r.weight() )
return false;
}
這就使程式員可以在結點類vehicle的基礎上建立像car和truck這樣的新類,他們只需要描述並實現與vehicle不同的東西。
這通常被稱為“通過差異做程式設計”,或者通過“擴充做程式設計”。
car本身也可以更進一步派生:
class ambulance : public car, public emergency{
public:
ambulance();
//覆蓋相關的car虛函數
void turn (Direction);
//覆蓋相關的emergency虛函數:
virtual void dispatch_to(cost Location&);
//……
//添加ambulance的特殊函數
virtual int patient_capacity(); //擔架數
//……
};