面向对象OOP
类与类之间的关系
- 继承
- 组合/复合
- 委托
复合(COMPOSITION 表示has-a)
概念理解
1 | template< class T , class sequence = deque<T> > |
其中对于template< class T , class sequence = deque> 的意思为默认 sequence 的类型为 deque
1 | template< class T > |
即queue里面的所有功能都没有自己写,他都是通过 C 来调用 deque 的成员函数来完成的,所有的功能都在 deque 中已经完成了,而 queue 是借用 deque 已经完成的功能来实现自己的功能。
对于上述的特例,进一步阐述 composition(复合) ,因为* deque* 的功能比较强大,而 queue 的功能都能通过借用 deque 来完成;这是 23种设计模式中的适配器模式 Adapter(适配,改造),简单的说即: A 拥有 B 则为 composition 。
生命周期上来看,内外部是同时的
内存分析:

套娃
组合/复合关系的构造函数和析构函数

对于 composition(复合) 而言,其构造函数是由内而外的,比如说类 A 中拥有类 B ,则类A的构造函数首先调用内部的类 B 的 default(默认) 构造函数,之后才执行自己的构造函数;但是当类 B 含有多个构造函数时,此时编译器不知道该调用哪一个构造函数,则此时需要程序设计者在写 composition(复合) 的构造函数时写上具体调用类B的哪一个构造函数。
委托(DELEGATION,COMPOSITION BY REFERENCE)
概念理解
1 | //handle 接口 指针指向为string实现所有功能的类StringRep |
委托也可以看做是一种复合,但是他是使用指针相连
string内有StringRep指针指向,string随时可以委托任务给StringRep来做
生命周期上来看,他们是不一致的,不同步,string可能会先创建,StringRep在使用时创建
这种pImpl机制,在C++的pImpl——编译防火墙中有单独介绍

要注意一个点,a要改变hello,不能影响b和c,当要改变时,将使用写入时复制(英语:Copy-on-write,简称COW)机制,创建一个副本提供给a修改,过程如下图所示。更多可参考写入时复制(Copy-on-write)机制
例子中利用这一特性实现了引用计数,即实现了多个字符串对象共享同一内容(内存地址)的字符串

相关设计实践
组合模式

在计算机文件系统中,有文件夹的概念,文件夹里面既可以放入文件也可以放入文件夹,但是文件中却不能放入任何东西。文件夹和文件构成了一种递归结构和容器结构。
虽然文件夹和文件是不同的对象,但是他们都可以被放入到文件夹里,所以一定意义上,文件夹和文件又可以看作是同一种类型的对象,所以我们可以把文件夹和文件统称为目录条目,(directory entry).在这个视角下,文件和文件夹是同一种对象。
所以,我们可以将文件夹和文件都看作是目录的条目,将容器和内容作为同一种东西看待,可以方便我们递归的处理问题,在容器中既可以放入容器,又可以放入内容,然后在小容器中,又可以继续放入容器和内容,这样就构成了容器结构和递归结构。
原型模式

子类通过构造函数创建的对象添加到父类的数组(原型数组)中去,父类通过数组中的原型调用clone来得到原型(子类对象)的副本
继承(Inheritance 表示is-a)
C++三种继承方式
public:
private:
protected:
内存分析 & 继承关系的构造函数和析构函数

子类对象中有父类的成分
父类的析构函数必须是虚函数,否则会出现undefined behavior
继承与虚函数
概念
在任何一个成员函数之前加上virtual关键字,就是一个虚函数
在继承关系中,数据可以被继承下来,可以从内存的角度看。函数也可以,但不能从内存的角度看,函数的继承继承的是调用权,即:子类可以调用父类的函数——子类继承了父类,拥有父类函数的调用权
成员函数分为三类:
- no-virtual函数,非虚函数:不希望子类/派生类重新定义(override,复写)它
- virtual函数,虚函数:希望子类重新定义(override,复写)它,且父类已经有默认定义
- pure virtual函数,纯虚函数:子类一定重新定义(override,复写)它,父类中没有默认定义(其实是可以有定义的)