该条款主要介绍两种复合规则:
第一种是has-a:当你程序描述的是实际的东西时,大都是这种关系:人有名字,学校有教室等等;
第二种是“由XX实现”,比如,集(set)由链表(list)实现等等;
class Address
{
public:
string country;
string province;
string city;
};
class Person
{
string name;
Address address;
};
当要定义一个Person类时应该这样写,而不是用Person去public继承Address,虽然这样做也能让一个人有地址,但是它却违背了public表示is-a的关系。人又不是一个特化了的“地址”。所以,这里使用复合会更合适。
对于第二种规则,看如下代码:
template<typename T>
class Set
{
public:
bool member(const T& item)const
{
return find(rep.begin(),rep.end(),item) != rep.end();
}
void insert(const T& item)
{
if(!member(item))
rep.push_back(item);
}
void remove(const T& item)
{
typename list<T>::iterator it = find(rep.begin(),rep.end(),item);
if(it != rep.end())
rep.erase(it);
}
size_t size()const
{
return rep.size();
}
void print()
{
list<T>::iterator it = rep.begin();
for(;it != rep.end();++it)
cout<<*it<<"\t"<<endl;
}
private:
list<T> rep;
};
这里把list对象定义为成员变量,而不是让自定义的set去继承list,如果继承的话,那么就意味着is-a关系,对于list的合法操作,对于set同样合法。但是,list可以插入重复的元素,而set却不可以,这违反了is-a的含义。
虽然与标准库的set相比,这个例子还是有些瑕疵,因为标准库每次插入元素后,都会自动排序。而这里却不行。总之,复合与public继承完全不同,它意味着has-a或者通过XX实现。