【Effective C++】对象之间的复合(composition)关系 —— has a 以及 is-implemented-in-terms-of

复合关系

当某种类型的对象内含其他种类型的对象时,它们之间便是这种复合关系。比如:

class Address { //... };
class PhoneNumber { //... };
class Person 
{
public:
	//...
private:
	std::string name;
	Address address;
	PhoneNumber voiceNumber;
	PhoneNumber faxNumber;
};

在这里例子中,Person 对象就由 std::stringAddressPhoneNumber 复合而成。


has-a 以及 is-implemented-in-tems-of

之前说过,public 继承就意味着 is-a 的关系。对于复合,它也有它对应的含义,它有两个意义。复合意味着 has-a 或者 is-implemented-in-terms-of。
上面的 Person class 就是 has-a 的关系。比较麻烦的是区分 is-a 和 is-implemented-in-terms-of 的关系。

比如说,你需要写出一个模板类,来实现由不重复对象组成的容器。你的第一反应,当时是直接使用 stl 中提供的 std::set 容器。但是这个容器背后是由红黑树实现的,虽然查找、插入、删除的速度都在对数级,但是每个元素都有三个指针的额外开销。你不希望用空间换时间,所以想自己另外实现一个模板类。
经过考虑之后,你决定顶层用 stl 中的 std::list 去实现 std::set 的功能。要想调用 std::list 。当然有两种实现形式:第一是继承它,这样就可以获得它的成员;或者是内含它的对象或指针,通过这个对象或指针去调用它的成员。如果你打算采用第一种方式:

template<typename T>
class MySet : public std::list<T> { //... }

看起来很美好,其实不是。之前也反复说过,public 继承意味着 is-a 的关系,对于基类来说任何有意义的行为对于子类来说也都需要有意义。但是在这里,std::list 是可以拥有相同的数据的,而 MySet 不行。所以,MySet 是一种 std::list 并不为真,因为某些对于 std::list 为真的东西对于 MySet 而言并不为真。
正确的做法,是让 MySet 内含一个 std::list 对象:

template <typename T>
class MySet
{
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 MySet<T>::member(const T& item) const
{
	return std::find(rep.begin(), rep.end(), item) != rep.end();
}

template<typename T>
void MySet<T>::insert(const T& item)
{
	if(!member(item))
		rep.push_back(item);
}

template<typename T>
void MySet<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 MySet<T>::size() const
{
	return rep.size();
}

这里的 MySetstd::list 就是 is-implemented-in-terms-of 的关系。

你可能感兴趣的:(Effective,C++)