主要有三种关系:继承、复合和委托。
1.复合 composition has-a
template <class T, class Sequence = deque<T>>
class queue
{
...
protected:
Sequence c;//底层容器
...
};
上述代码可以写成下图,便于理解
Adapter设计模式:将deque改造成queue
template <class T>
class queue
{
...
protected:
deque<T> c;//底层容器
public:
// 以下完全利用c 的操作函數完成
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference front() { return c.front(); }
reference back() { return c.back(); }
//
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_front(); }
};
黑色菱形:黑色表示有内容,菱形一端是容器
两层composition,如下图
composition关系下的构造和析构:
- 构造由内而外:Container 的構造函數首先調用Component 的default 構造函數,
然後才執行自己。(如果默认构造函数不符合要求,需要自己写)Container::Container(...): Component(){...};
- 析构由外而内:Container 的析構函數首先執行自己,然後才調用Component 的
析構函數。Container::~Container(...){...~Component()};
2.委托delegation (composition by reference 指针)
在任何时间点都可以将任务委托给对方。
composition: 生命一起出现;delegation:生命可能不同步
例:白色空心表示指针
// file String.hpp
class StringRep;
class String {
public:
String();
String(const char* s);
String(const String& s);
String &operator=(const String& s);
~String();
. . . .
private:
StringRep* rep; // pimpl
};
// file String.cpp
#include "String.hpp"
namespace {
class StringRep {
friend class String;
StringRep(const char* s);
~StringRep();
int count;
char* rep;
};
}
String::String(){ ... }
...
pImpl设计模式:pointer to implementation,handle/body
将指针指向外部实现类
好处:指针可以灵活指向任何实现类,客户端保持不变
例:reference counting,三个字符串共享一个hello,节省空间
3.继承 inheritance is-a
继承的语法如下图:
struct _List_node_base
{
_List_node_base* _M_next;
_List_node_base* _M_prev;
};
template<typename _Tp>
struct _List_node:public _List_node_base
{
_Tp _M_data;
};
三种类型继承:public private protected,其中public最常用
上述例子是父类的数据被继承,继承最有价值的部分其实是与虚函数搭配
继承关系下的构造与析构
- 構造由內而外:Derived 的構造函數首先調用Base 的default 構造函數,然後才執行自己。
Derived::Derived(...): Base(){...};
- 析構由外而內:Derived 的析構函數首先執行自己,然後才調用Base 的析構函數。
Derived::~Derived(...){...~Base()};
注:父类的析构函数必须是虚函数,否则会出现undefined behavior