C++ 学习笔记 4
C++学习笔记4
面向对象,类与类之间的关系
继承inheritance、复合composition与委托delegation
复合(组合)composition,表示has-a
其实就是构建类的时候放进去一个其他类的对象啦。进而就可以使用这个对象的函数来实现自己想要的功能。
比如queue是用deque实现的,只开放了一部分功能。这叫做Adapter(适配器)。
复合关系下的构造和析构
构造由内向外,从被拥有者构造起,具体解释是:Container的构造函数首先调用Component的default构造函数,然后才执行自己。
析构由外而内,首先执行自己,再调用component的析构函数,
委托delegation,用引用来复合
有一个指针指向另外一个对象。这个对象未必存在,在需要调用时再使用。用指针相连。
二者寿命不一致。在复合中是共存亡,在委托是需要再创建。
pimpl( pointer to implementation)
一个类实现函数接口,并用一个指针指向具体实现的类。或称handle / body
.
可以在保证接口不变动的情况下,改动底层实现,还不会影响用户的使用。
用于共享数据的实现
可以有计数变量,指向同一个数据。但注意修改时不能改变别人的数据,需要提供一个副本来修改。
继承inheritance,表示is-a
语法,使用 :
struct _List_node : public _List_node_base{
_Tp _M_data;
}
-
struct可以视为与class一样,非常类似
-
三个作用范围关键字都可以用于继承,因此继承有三种
- public才是is-a 的关系
-
父类所拥有的成员变量是被继承下来的。即子类也有同样的成员变量。进一步到虚函数的应用。
构造与析构
子类的对象里有父类的成分(part)在里面。
构造由内而外,子类先调用父类的default构造函数,然后才执行自己的ctor。
析构由外而内,先执行自己的析构函数,再调用父类的析构函数。
父类的dtor必须是虚函数virtual,否则会出现未定义行为ub。
虚函数
三种成员函数
non-virtual函数:子类不应该重新定义(override,覆写)这个函数。
virtual函数:子类可以重新定义,但是是有默认的定义的。
纯虚pure virtual函数:子类必须重新定义。且没有默认定义。
class Shape{
public:
int ID() const;//non-virtual
virtual void error(const std::string& msg);//impure virtual
virtual void draw( )const = 0;//pure virtual
}
template method模板函数
指一些函数里,所调用的部分函数只设计好位置和接口,具体实现由后续具体完成。
继承+复合关系下的构造与析构
有如下两种情况:
构造谁先谁后?
第一种,通过如下代码来体现。
#include <iostream>
using namespace std;
class Base{
public:
Base(){
cout<<"Base here"<<endl;
}
};
class Component{
public:
Component(){
cout<<"Component here"<<endl;
}
};
class Derived : public Base{
public:
Derived(){
cout<<"Derived here"<<endl;
}
private:
Component c;
};
int main() {
Derived d;
return 0;
}
//output
//Base here
//Component here
//Derived here
//Process finished with exit code 0
可知是先执行inheritance,再compont
第二种,先component,再inheritance,对代码稍作改动即可。
委托+继承 composite组合模式(部分整体模式)
特征
- 整体的结构应该是一棵树,
- 所有的组件应该有一个共同的父类(有共同的本质),
- 这个父类使得组件中的共同的本质可以提取出来(有了共同语言(父类)),进行互融
图例
组成与功能
primitive
- 基本的,个体的;或者称为原语(不太合适),意思就是一种不能包含component的子类。
- 比如文件,
Composite
- 复合物,组合物。是一个容器,可以容纳primitive和composite自己
- 如果给primitive和composite找一个共同语言及父类,就可以解决了。
- 即容纳的对象不写死,可以是composite也可以是primitive。
- 容纳的对象要写成指针。放对象进去,两者毕竟不一样,大小什么的都不一样。
- 拥有add函数,可以加进来component。参数也是component就可以。
Component
- 是共同的父类,“共同语言”
- 需要定义一个无动作的add函数,是虚函数。不是纯虚函数,因为primitive不能定义add函数。
prototype原型模式
设计者还不知道将来的class会叫什么名字。将来的class创建的东西可以被框架所看到,就可以了,
子类自己创造自己,创造一个static的对象。这个原型可以被父类看得到。因此把原型放到父类的一个数组空间中,可以被父类访问。
构造函数写为private。
父类提供一个addPrototype函数,即把指针放到拥有的容器中。然后对子类调用这个函数,就可以提供给父类。
子类还需要准备一个clone函数,返回new一个子类对象。父类通过他可以访问的数组,调用这个clone函数,就可以做出一个副本。