第三周
前两周讲的是单个类的设计。即基于对象编程。
本周是讲类与类之间的关系,即面向对象编程
复合(组合)composition,继承inherit,委托delegate
利用这三种方法,基本可以写出任何想要的类。
l Composition, 表示has-a
Composition概念早就存在,在c语言的struct中,使用了别的struct或者string等,都是组合(c语言实现面向对象就是用了这个特性)
看下图,顺便看一下uml图
Adapter,
queue中含有deque,即queue和deque是复合关系。(即只要A含有B,则就是一种复合关系)。但看代码,queue中的功能,都由dequeue完成。Dequeu的功能比较强大,就比较特殊了,成为一种adapter模式。
再从内存角度考虑复合关系
即,container包含了component,内存也相应的加上component的内存大小。
composition的构造和析构
构造,由内而外,
Conainter::Container():: Component() {…} //编译器会自己去构造Component对象
container的构造函数首先调用component的default构造函数
析构,由外而内
Container的析构先调用自己,然后再调用Component的析构函数(编译器帮助完成,我们只要管理好Container的构造和析构就可以)。
如果Component的构造函数有多个,则需要显式的调用构造函数。
l Delegation委托,composition by reference
一种微弱的组合关系,不是含有component,而是含有component的指针。
l 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 //public 继承
{
Tp _M_data; //诠释了数据继承
};
继承有三种方式,public,protected,private继承。最常用的public继承,是说is-a关系。例子可以说List_node is a List_node_base。
从内存角度看,
同复合关系。
Inheritance关系下的构造和析构
构造由内而外
Derived的构造函数首先调用Base的default构造函数,然后执行自己。
析构由外而内
Derived的析构函数首先执行自己,然后才调用Base的析构函数。
与复合一样,Base的默认构造和析构由编译器完成。
Base class的dtor析构函数必须是virtual,否则会出现undefinedbehavior。
Inheritance(继承)with virtual functions
继承搭配着虚函数。
子类可以继承父类的所有内容,包括数据和函数。从内存角度,可以继承数据;对于函数,不能从内存角度理解,而是子类继承了父类的函数调用权。
函数分为三种情况
non virtual function:你不希望derived class重新定义override
virtual function:希望derived class的重新定义override。已有默认定义。
pure virtual:你希望derived class一定要重新定义。没有默认定义。
在例子中,objectID比如是个流水号,每种对象都是一样的,因为使用非虚函数;Error函数,base class有一个默认的实现方法,比如打出一条错误语句,但如果子类有更好的实现,允许它重写,因此写成虚函数;draw函数则是一定是要重写的,因为每种形状的画法不同,一定要重写,因此设计成纯虚函数。
看看这例子,
这是从MFC摘出来的一段代码。
CMyDoc继承了CDocument。看上面那个曲线调用图,在main中,声明了CMyDoc对象(子类),当调用OnFileOpen时,会调用其父类的方法,然后执行到Serialize时,发现其为virtual类型,并且在子类中已经有virtual定义,所以就会去执行子类的这个方法。这是virtual的关键。——这是赫赫有名的templatemethod模式。
C++中是虚函数,java中的接口。
那为什么调用调用父类的方法时,会调用到其子类的虚函数去?看灰色部分,因为会有一个隐含的this指针。
Inheritance+composition,继承加组合
如果子类中既有继承,又有组合,内存布局是什么样的?构造的时候,会先构造那个?可以写一个demo,看看使用的编译器是怎么做的?
总结,在多个关系中,功能最强大的是委托+继承,
以Observer观察者模式为例,
最后一节
Object Model
重点的东西,再次强调一下:
主要包括
继承关系下的构造和析构
组合关系下的构造和析构
继承+组合关系的构造和析构