复合是类型之间的一种关系,当某种类型的对象内含它种类型的对象,这种关系便是复合。例如下面这段代码,就用到了复合
class Address{ ...... };
class PhoneNumber{ ...... };
class Person{
public:
...
private:
std::string name;//合成成分物
Address address;//同上
PhoneNumber voiceNumber;//同上
PhoneNumber faxNumber;//同上
};
区分public继承和复合。public继承是is-a(是一个),复合是has-a(有一个)或is-implemented-in-terms-of(根据某物实现出)。
就如上面这段代码,我们可以说人有一个名字,有一个住址,不能说人是一个名字,人是一个住址。当复合发生在应用域,表现出has-a的关系。程序中的对象相当于你塑造的世界中的某些事物,例如你如这个世界里的人,汽车等,这样的对象(人、汽车)属于应用域,此时我们说世界有人,世界有汽车。例如上面这段代码,name,address,voiceNumber,faxNumber,就是我塑造的人这个类里面的事物,所以这里的复合是应用域,是has-a关系。(其实我觉得可以理解成组成部分吧,一个类的组成部分,属于应用域。就像人这个类由名字、地址、电话号码组成)当复合发生在实现域,表现出is-implemented-in-terms-of关系。那些实现细节的对象属于实现域(大概是为了实现类的某种功能而定义的成员对象属于实现域吧。)
来看书上举的例子;用list实现set,最先想到的办法是让Set public继承list
template <typename T>
class Set:public std::list<T>{......};
这种做法是错误的,因为public继承意味着is-a,也就是Set是一个list,然而,Set是不允许插入重复元素的,你插入两个1,最终的Set中只有一个1,而list不一样,list就会有两个1,list 是可以重复插入相同元素的。那么这种关系就不符合is-a,于是我们就不能利用public继承。考虑复合,根据list对象实现Set对象
template <class 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;
};
//检查元素是否有重复的
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>::member(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();
}
从上面这段代码可以看出,我们利用list实现了我们的Set,这种关系就是is-implemented-in-terms-of(利根据某物实现出)
请记住:
1.复合的意义和public继承完全不同
2.在应用域,复合意味着has-a(有一个)(某类有什么时就是has-a)。在实现域,复合意味着is-implemented-in-terms-of(根据某物实现出)(某类利用其他类对象实现了自己的功能时)