侯捷老师视频笔记----c++面向对象高级编程

以下记录是从侯捷老师视频的c++上的第11节视频开始。

复合

先从Compositon开始讲起,其实在C语言中也见到过,一个结构体里面包含另外一个结构体,在C++中复合也是一样的,侯捷老师以标准库来形象的说明了这种情况,在queue类中包含了deque类的某些方法。这张图很好的体现了queue是由deque实现的,就是把deque的部分方法给了queue(deque是两端可进可出的队列,而queue是一端进一端出)。
在这里插入图片描述
2个类的关系在上图中,实心表示复合关系,那这2个对象怎么产生,先后顺序是什么?
在这里插入图片描述

下面这张图表现了queue类中有一个deque类,deque类中又用了Itr结构体
在这里插入图片描述

委托

接下来再谈谈委托(Delegation)关系,委托是利用指针包含另一个类,左边有一个右边,但是这个有只是一个指针,有点虚,所以是空心的
在这里插入图片描述
string类只是对外的接口,真正的实现都在stringrep类里,当左边需要动作的时候,就去调用(委托)右边,被称为Pimpl(pointer to implementation),有一个指针去指向为我实现所有功能的类,这种手法的好处在于,这个指针还可以去指向不同的实现类,去实现不同的功能,右边不管怎么变动都不影响string类也就不影响客户端,string类也永远不用再编译。

上述代码的实现如左下图所示,abc3个string指向一个指针,称为引用计数(共享特性)有多个字符串指向同一个hello,这时候abc互相不知道大家都在用同一个内存,如果改变a就会影响其他,怎么做到不影响呢,当a想改变时,整个系统就copy一份给a,让a改,然后降低count,称为copy and write。

继承

public 继承表示is a,派生类是一种基类的东西,同样的继承了基类的数据。子类包含了父类,所以在构造子类之前要先构造父类,在子类的初始化列表上,同样的在析构子类的时候,也是先析构子类,再析构父类,和复合非常相似。
其中继承是:数据被继承下来占用了内存,函数是继承了其调用权
在这里插入图片描述
一个类中成员函数分为3种:

non-virtual:不希望派生类对其进行重写(override).
virtual:希望派生类对其进行重写(override).
pure-virtual(纯虚函数):希望派生类一定要对其进行重写
在这里插入图片描述

继承搭配虚函数使用才是他最有用的地方
打开菜单,弹出对话框,查找或者选择文件名称,按下打开,程序收到名称校对文件名称,查找文件,打开文件读出来。读的内容不一样所以其他都可以事先写好。以下是一个例子:
比如下图,有很多常用的方法可以先写好,但是有某个方法不会写,就等到让他的子类取写,所以可以把他定义为虚函数,函数体为空,子类重新定义(覆写)他,如果设成纯虚函数,子类就一定要去重写他,这样要求太严苛,万一没写就出错了,所以还是设虚函数比较合适。

类中的成员函数都是以this为调用的,所以this->Serialize()在以CMyDoc的对象调用以后,传入的是myDoc的地址,最后调用了其函数,实现了具体实现

这种方法是一种设计模式Template Method,Template Method就是一种写好一个框架把可以设定的都设定好,然后再实现过程中以虚函数的方式让具体实现交由继承它的类,完成各种不同的功能。
在这里插入图片描述

在这里插入图片描述

复合和继承的情况

再看一下复合的关系,继承与复合同时存在时,在创建对象的时候,又该怎么进行构造呢
在这里插入图片描述
下半个图很明显,我要构造派生类,我就要先构造父类,构造父类,我就要先构造其中包含的类。

而上面的图,当我们需要构造派生类时,肯定的是派生类是最后构造的,那么父类和复合类的先后顺序是什么样的呢,在不同的编译器上可能会有所不同。在WINDOWS下利用VS2019,实现以下的函数

#ifndef CONMPOSITON__INHERITANCE_H
#define CONMPOSITON__INHERITANCE_H
#include <iostream>
using namespace std;
class A{
   
   
public:
	A(){
   
    cout << "A is make" << endl;}
	~A(){
   
    cout << "~A is delete" << endl;}
};
class C{
   
   
public:
	C() {
   
    cout << "C is make" << endl;}
	~C(){
   
    cout << "~C is delete" << endl;}
};
class B:public A{
   
   
public:
	B(){
   
    cout << "B is make" << endl;}
	~B(){
   
    cout << "~B is delete" << endl;}
private:
	C c;
};
 
 
#endif
int main() {
   
   
	B b;
	return EXIT_SUCCESS;
}

在这里插入图片描述

我们发现父类先被构造,然后是复合类,然后才是子类,析构与之正好相反。

委托和继承的情况

比如像下面这种情况,以一个ppt的窗口为例,来讲解委托与继承的结合:要开好几个窗口,但是实际上数据只有一份,一个地方变了数据,其他也就跟着变化了。这是利用多个窗口来显示同一份数据,左边是4个窗口都显示一样的,右边是同一份数据利用不同的图形去表示。
在这里插入图片描述
要实现这样的功能就必须呈现数据和储存数据的class之间要具备关联性,如果数据有变换,这些窗口都需要变化。我们用subject去储存数据,用observer去观察数据,我们让subject可以拥有很多个observer(委托,指针实现),因为我们要开出很多个窗口去观察它。

下面这个图就实现了这种需求,左边一个类委托另一个类,去更新数据,然后这个类可以被继承,这时候委托的指针和之前讲的委托不一样的是,当时只有一个string的实现,现在传过去的是一个类,这个类可以不断的被继承,实现不同种类的功能(比如,让窗口显示不一样)。
在这里插入图片描述

class subject{
   
   
private:
    int m_value;
    vector<observer*> m_views;//一个容器包含多个窗口,就可以实现多个窗口
public:
    void attch(observer* obs){
   
   
        m_views.push_back(obs);//谁要使用就来注册,开辟窗口
    }
    void set_value(const int& value){
   
   
        m_value = value;
        notify();   //每次改变数据都去更新
    }
    void notify(){
   
   
        for(int i = 0;i<m_views.size();i++)
        {
   
   
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值