复合(Composition)
复合其实是一种 has-a 的关系,就是说一个类里面有其他类的对象
例如在STL标准库的实现中,queue里面有一个deque
template <class T>
class queue {
//...
protected:
deque<T> c;
public:
//以下功能完全利用 c 的操作函数完成
bool empty() const { return c.empty(); }
size type size() const { return c.size(); }
//
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_front(); }
};
queue的一些功能完全借助deque来实现。
复合关系下的构造与析构
- 构造函数是由内而外
Container的构造函数首先调用Component的default构造函数(编译器帮助我们做的)
然后才执行自己
Container::Container{...}:Component(){...}
- 析构是由外而内
Container的析构函数首先执行自己,然后才调用Component的析构函数
Container::~Container{...}{... ~Component() };
如果不想调用另一个对象的默认构造函数,那就要显示调用
继承(Inheritance)
继承是一种 is-a 的关系,
基类中函数有三种:
- 普通函数
- 虚函数
- 纯虚函数
其中,如果在基类中写成纯虚函数,那么派生类(derived class)中一定要重新定义该函数,就是说派生类要有该虚函数的自己的版本
如果是虚函数,那么在基类中已经有了默认定义,派生类中可以选择重新定义。
public继承下,父类中的数据是被完全继承下来的。
继承关系的构造与析构
- 构造由内而外
- 析构由外而内
继承关系下构造与析构顺序与复合关系下相同。
当一个类同时有继承和复合时,是先调用基类的构造函数还是另一个复合的类的构造函数呢?
析构函数的顺序呢?谁先谁后并不重要,只是看一下。
一个测试程序看一下结果
#include <iostream>
using namespace std;
class Base{
public:
Base()
{
cout << "I'm base class!" << endl;
}
~Base()
{
cout << "Base dead!" << endl;
}
};
class Com{
public:
Com()
{
cout << "I'm Composition class!" << endl;
}
~Com()
{
cout << "Composition dead!" << endl;
}
};
class Test:public Base{
public:
Test()
{
cout << "I'm Test class!" << endl;
}
~Test()
{
cout << "Test class dead!" << endl;
}
Com ch;
};
int main()
{
Test tt;
return 0;
}
以下是在windows下使用Dev-c++,GCC 4.9.2的执行结果:
构造函数执行顺序是先执行基类的构造函数,再执行复合的对象的构造函数
析构函数执行顺序是先执行复合的对象的析构函数,再执行基类的析构函数
以上说明基类是“最里面的”
也刚好验证了上面所说的构造是由内到外,析构是由外到内
委托(Delegation)
A类中有一根指向另一个类B的指针
当创建A类对象时,B类对象并不被也创建,而在复合关系中,两个类的对象是同时创建
委托关系可以委托B类帮自己具体实现,
这种方法有个名词pImpl(Pointer to IMPLementation),简单理解就是接口与实现分离
(后面继续再整理)