複合(composition)是類型之間的一種關係,當某種類型的對象內含它種類型的對象,便是這種關係:
class Address {...};
class PhoneNumber {...};
class Person {
public:
...
private:
std::string name;//合成成分物
Address address;//合成成分物
PhoneNumber voiceNumber;//合成成分物
PhoneNumber faxNumber;//合成成分物
};
public繼承帶有is-a的意義。複合也有它自己的意義。實際上它有兩個意義。複合意味has-a或is-implemented-in-terms-of。那是因為你正打算在你的軟體中處理兩個不同的領域。程式中的對象其實相當於你所塑造的世界中的某些事物,例如人、汽車、等等。這樣的對象屬於應用域(application domain)部分。其他對象則純粹是實現細節上的人工製品,像是緩衝區、互斥器、尋找樹等等。這些對象相當於你的軟體的實現域(implementation domain)。當複合發生在應用域內的對象之間,表現出has-a的關係;當複合發生在實現域內則是表現is-implemented-in-term-of的關係。
上述的Person class示範的是has-a關係。
比較麻煩的是區分is-a和is-implemented-in-term-of這兩種對象關係。
假如你想製造出一組class用來表現有不重複對象組成的sets。而stl中sets以平衡尋找樹(balanced search trees)實現而成,每個元素耗用3個額外指標。而你的程式空間比速度重要。所以你決定複用list template 採用linked lists來實現自己的set。
你想讓set繼承stl::list:
template<typename T>
class Set : public std::list<T>{...};//將list應用於set。錯誤做法。
public繼承是is-a關係,但set不是一種list,因為對list為真的某些事情對set對象並不為真。例如,list可以內含重複元素,如果30被安插到list<int>兩次,那個list將內含兩筆30,如果30被安插到set<int>兩次,set只內含一筆30.
所以這兩個classes之間並非is-a關係。不應該是public繼承,正確的做法是,set對象可根據一個list對象實現出來:
template<typename T>
class Set {
public:
bool member(const T& item) const;
void insert(const T& item);
void remove(const T& item);
std::size_t size() const;
private:
std::list<T> rep; //用來表述set的資料
};
set的成員函數可以大量依賴list及標準程式庫其他部分來完成,所以其實現很直觀也很簡單,只要你熟悉stl編寫程式:
template<typename T>
bool Set<T>::member(const T& item) const
{
return std::find(rep.begin(), rep.end(), item) != rep.end();
}
template<typename T>
void Set<T>::insert(const T& item)
{
if(!member(item))
rep.push_back(item);
}
template<typename T>
void Set<T>::remove(const T& item)
{
typename std::list<T>::iterator it = std::find(rep.begin(), rep.end(), item);
if (it != rep.end())
rep.erase(it);
}
template<typename T>
std::size_t Set<T>::size() const
{
return rep.size();
}