当前课程知识点:基于Linux的C++ >  第八讲 链表与程序抽象 >  8.11 抽象链表(二) >  LinuxCPP0811

返回《基于Linux的C++》慕课在线视频课程列表

LinuxCPP0811在线视频

LinuxCPP0811

下一节:LinuxCPP0812

返回《基于Linux的C++》慕课在线视频列表

LinuxCPP0811课程教案、知识点、字幕

我们看怎么使用 你就会明白了

假设我实现了一个函数叫PtTransformIntoString

它里面带着两个参数

一个是const char * format 一个是point

你看它的实现

我定义一个buffer 缓冲区

然后如果有一个point

我们就按照它的那个format传进来的格式

生成它对应的字符串

然后我们返回这个字符串

这个字符串的格式

就不是刚才那个“(%d,%d)”格式

你随便 你用“(%d,%d)”也行

你用“[%d,%d]”写也行

哪怕“<%d,%d>”也成

也就是说这个时候

你可以按照特定的一个字符串格式

来设定这个点的输出信息

这个就是我们的PtTransformIntoString这个函数

我做了修正

关键的是你看我们怎么去调用它

我会写一个函数叫DoPrintObject

打印特定的对象

传一个ADT类型的参数 传tag

因为这是一个回调函数

它将会被LlTraverse所调用

当你有了抽象的链表库和抽象的点库之后

你想使用这个抽象的链表库

来存储这个抽象的点

然后你就会写一个函数来调用LlTraverse

来遍历这个抽象的链表库里面全部的点

然后把它数据给打印出来

你要想完成这样任务

你就会写这样的函数LlTraverse

你就会这样调用

LlTraverse(list, DoPrintObject, “(%d,%d)”)

比如讲当你想“(%d,%d)”格式调用它的时候

那么你就按照这个格式传一个字符串进去

这个就是它的第三个参数 附加参数

现在明白了

我们现在有一个抽象的链表库

有一个抽象的点库

然后我要写一个程序

使用抽象链表库来存储我们抽象的点库

注意抽象的链表库是我写的

抽象的点库可能是张三写的

你呢 要使用我和张三

写的那段程序代码来实现你的程序

那么当你想按照一个特定格式

输出这些点信息的时候

我们就要调用LlTraverse这个函数

传递抽象的链表 传递回调函数

你遍历这个链表的时候想打印它嘛

想输出它的信息嘛

传递回调函数DoPrintObject 传打印的格式

这个就是附加的参数

LlTraverse 当接收到这个链表

还接收到了回调函数之后

它在内部调用的时候

就会调用这个回调函数

去执行你写的那段程序代码

同时将这个回调函数的那个附加的参数

它接收过来的第三个参数

转手扔给DoPrintObject

看我们的DoPrintObject

第一个参数ADT e 第二个参数ADT tag

第一个参数是什么

是我们点的结构体的地址

就是指向那个点结构体的指针

tag是什么 ADT

它实际上是什么 实际上是char *

现在我们很明确

在DoPrintObject里面 我们怎么办

调用PtTransformIntoString

把tag转换成const char *

作为第一个参数传进去

第二个参数是e 转换成PPOINT 传进去

那么PtTransformIntoString

就会以tag所指定的格式

将e这个点转换成一个字符串

然后我printf打印这个字符串 printf输出

你用cout也行 相当重要的一个地方

这个就是我们的回调函数的参数

那么你可能就会说

如果我不写这个回调函数的参数行不行呢

你不是就是这个特定的格式吗

我就直接写在DoPrintObject

这个函数的实现里面哪

写小括号对不就完了吗

不能啊 对吧

你不能把“(%d,%d)”写在这里啊

你一写在这里就只能做小括号对了吗

不能做中括号对了吗

对吧 不就不能改了嘛

你必须作为参数啊

你也不可能作为参数放在这里

你一旦直接写const char * format这个参数

放到DoPrintObject里面

那么不就意味着

这个函数第二个参数它不是tag了吗

它本来就需要一个ADT类型的参数

作为一个附加参数

所有的信息都可以表示

那你干嘛使用一个具体的信息

放在那个地方呢

当然使用一个单一的抽象附加信息表示

要更通用啊

这个就是我们ADT tag这个附加参数的意义

你看到这个有趣的地方吧

我用一个附加参数作为我们的映射函数

就是我们的回调函数的主调函数 对吧

和我们的回调函数

两者信息交互的一个关键点

就是它们交流的信息 就用它来代表

在这个里面 程序的参与者

我们可以说有三个人

抽象链表的设计者 点库的设计者

使用这两者在链表库里面

存储点数据的那个程序员

这里面是三个人

当然我们现在这个作为示例

三个都是我写的 对吧

但实际上我们编程的时候

它可能是三个人

互相之间完全不了解其它人的实现细节

他不知道抽象链表是怎么实现的

它的接口是什么 都不知道

设计链表库的人

他不知道点库是怎么实现的

点库接口是什么 他也不知道

只有使用抽象链表库

来存储点的那个程序员

他才知道抽象链表库的接口是什么

点库的接口是什么

但是对于抽象链表库的实现是什么

点库的实现是什么

第三个程序员也一样不知道

他不需要知道 反正能用就行了 对吧

抽象的目的就体现在这里

我让这些模块尽可能地独立

你能用就行了

你压根就不需要知道它内部的实现细节

抽象的链表作为一个容器

和容器中的一个对象

我就把它独立开了 分离开了

我们的容器就用来表达

能够容纳其它数据对象集的

像这样一个东西

我们的抽象链表就是这样的

它能够容纳其它数据对象

我们的抽象链表做的就是这个事情

我们的点数据结构

就是我们的容器中的对象 对吧

两者是完全无关的

就像我前面那个例子

抽屉和抽屉里面所能够存的

铅笔、钢笔、笔记本、钱包

它有关系吗 它没关系

容器和容器所容纳的对象完全独立

这个就叫抽象

没有抽象的容器和抽象的点

这个事情是做不了的

我们编程的时候需要特别特别

注意这个问题

抽象是解决这些问题的关键

按照这样的一个实现

我们的抽象链表事实上

可以容纳任意类型的数据对象

什么东西都可以存 一点问题都没有

还有一些知识点我们需要知道

抽象链表中一旦要存储

一些目标数据对象的时候

那么这些目标数据对象的存储和删除

在编写程序的时候是需要特别去注意的

第一 你链表中的那个data域是不是一个指针

第二 data域是不是指向真正存在的

目标数据对象

如果不指向怎么办

如果指向怎么办

是否需要指向一个真正存在的

目标数据对象

这个目标数据对象是你动态分配的

还是静态分配的

这个都需要你在

使用抽象链表库的时候明确的

第三个 如果结点要被删除的话

我们的data域

所指向的一个目标数据对象

是否需要被删除

链表这个结点被删除了

data域所指向的目标数据对象

是不是需要删除

就像我们前面讲的

如果我是把一个int直接转换成void*

存在data域里面的

那我这个结点被删除的时候

目标数据对象不存在 所以不需要删除

那个data字段

它真地指向目标数据对象

当我删除这个结点的时候

那个目标数据对象是不是一定需要删除

虽然在大部分情况下真需要删除

但是也并不意味着每次总是这样

并不意味着一定需要删除

这个地方同学们一定要注意

编程的时候要非常非常小心才可以

第四个 如果需要删除 你怎么删除

第五个 抽象链表的设计者

能不能完成这样的删除任务

如果能 你就删就行了

第六个 如果你不能 你怎么办

这一点 你写程序的时候

必须要时刻地注意到

我们可以看到这样的一个例子

我这个数据对象如果需要删除

那我就提供一个函数指针类型

这就是DESTROY_OBJECT

销毁目标数据对象的一个函数指针类型

传递一个哑型指针ADT e

用来代表待销毁的

那个目标数据对象的地址

在LlDelete这个函数的实现中

我们要使用一个回调函数

作为它的函数参数:DESTROY_OBJECT destroy

这个destroy如果你传了一个非0值

不是NULL的一个值

那么我们就调用destroy所指向的那个

目标销毁函数 销毁它的目标数据对象

如果你传了一个NULL

我就不销毁 很明确吧

这个就是我们数据对象的存储与删除

一般要做的事情

所以说 如果你需要删除目标数据对象

那么正常情况下边

你需要写一个回调函数DoDestroyObject

然后在这个里面去销毁那个目标数据对象

你在调用LlDelete这个函数的时候

传递一个函数的入口地址给它

把DoDestroyObject函数的入口地址

作为第三个参数传给LlDelete

然后它就调用DoDestroyObject

替你销毁那个目标数据对象

如果你不需要删除目标数据对象

那么你就传递一个NULL给LlDelete

它就什么也不做

这就为我们编程提供了很大的灵活性

最后 我们的抽象链表库该怎么去设计

我们这里面当然会有一个

struct LIST *定义成PLIST

数据封装与信息隐藏

然后我们定义了三个函数指针类型

COMPARE_OBJECT、DESTROY_OBJECT、

MANIPULATE_OBJECT

重新修正了抽象链表库的接口

LlCreate没变 LlDestroy发生了变化

传递了一个销毁对象的回调函数

一个函数指针

LlAppend没变 LlInsert没变

LlDelete同样要传递

DESTROY_OBJECT类型的一个函数指针

LlClear当然也需要

LlTraverse需要传递一个操纵对象的回调函数

LlSearch要传递一个比较对象的回调函数

这个就是我们最终的抽象链表库的接口

基于Linux的C++课程列表:

第一讲 C/C++基本语法元素

-1.1 提纲

--LinuxCPP0101

-1.2 程序设计的基本概念

--LinuxCPP0102

-1.3 简单C/C++程序介绍

--LinuxCPP0103

-1.4 程序设计的基本流程

--LinuxCPP0104

-1.5 基本语法元素

--LinuxCPP0105

-1.6 程序设计风格

--LinuxCPP0106

-1.7 编程实践

--LinuxCPP0107

-第一讲 C/C++基本语法元素--编程实践提交入口

第二讲 程序控制结构

-2.1 提纲

--LinuxCPP0201

-2.2 结构化程序设计基础

--LinuxCPP0202

-2.3 布尔数据

--LinuxCPP0203

-2.4 分支结构

--LinuxCPP0204

-2.5 break语句

--LinuxCPP0205

-2.6 循环结构

--LinuxCPP0206

-2.7 编程实践

--LinuxCPP0207

-第二讲 程序控制结构--编程实践提交入口

第三讲 函数

-3.1 提纲

--LinuxCPP0301

-3.2 函数声明、调用与定义

--LinuxCPP0302

-3.3 函数调用栈框架

--LinuxCPP0303

-3.4 编程实践

--LinuxCPP0304

-第三讲 函数--编程实践提交入口

第四讲 算法

-4.1 提纲

--LinuxCPP0401

-4.2 算法概念与特征

--LinuxCPP0402

-4.3 算法描述

--LinuxCPP0403

-4.4 算法设计与实现

--LinuxCPP0404

-4.5 递归算法(一)

--LinuxCPP0405

-4.6 递归算法(二)

--LinuxCPP0406

-4.7 容错与计算复杂度

--LinuxCPP0407

-4.8 编程实践

--LinuxCPP0408

-第四讲 算法--编程实践提交入口

第五讲 程序组织与开发方法

-5.1 提纲

--LinuxCPP0501

-5.2 库与接口

--LinuxCPP0502

-5.3 随机数库(一)

--LinuxCPP0503

-5.4 随机数库(二)

--LinuxCPP0504

-5.5 作用域与生存期

--LinuxCPP0505

-5.6 典型软件开发流程(一)

--LinuxCPP0506

-5.7 典型软件开发流程(二)

--LinuxCPP0507

-5.8 编程实践

--LinuxCPP0508

-第五讲 程序组织与开发方法--编程实践提交入口

第六讲 复合数据类型

-6.1 提纲

--LinuxCPP0601

-6.2 字符

--LinuxCPP0602

-6.3 数组(一)

--LinuxCPP0603

-6.4 数组(二)

--LinuxCPP0604

-6.5 结构体

--LinuxCPP0605

-6.6 编程实践

--LinuxCPP0606

-第六讲 复合数据类型--编程实践提交入口

第七讲 指针与引用

-7.1 提纲

--LinuxCPP0701

-7.2 指针基本概念

--LinuxCPP0702

-7.3 指针与函数

--LinuxCPP0703

-7.4 指针与复合数据类型(一)

--LinuxCPP0704

-7.5 指针与复合数据类型(二)

--LinuxCPP0705

-7.6 字符串

--LinuxCPP0706

-7.7 动态存储管理(一)

--LinuxCPP0707

-7.8 动态存储管理(二)

--LinuxCPP0708

-7.9 引用

--LinuxCPP0709

-7.10 编程实践

--LinuxCPP0710

-第七讲 指针与引用--编程实践提交入口

第八讲 链表与程序抽象

-8.1 提纲

--LinuxCPP0801

-8.2 数据抽象(一)

--LinuxCPP0802

-8.3 数据抽象(二)

--LinuxCPP0803

-8.4 链表(一)

--LinuxCPP0804

-8.5 链表(二)

--LinuxCPP0805

-8.6 链表(三)

--LinuxCPP0806

-8.7 链表(四)

--LinuxCPP0807

-8.8 函数指针(一)

--LinuxCPP0808

-8.9 函数指针(二)

--LinuxCPP0809

-8.10 抽象链表(一)

--LinuxCPP0810

-8.11 抽象链表(二)

--LinuxCPP0811

-8.12 编程实践

--LinuxCPP0812

-第八讲 链表与程序抽象--编程实践提交入口

第九讲 类与对象

-9.1 提纲

--LinuxCPP0901

-9.2 程序抽象与面向对象

--LinuxCPP0902

-9.3 类类型

--LinuxCPP0903

-9.4 对象(一)

--LinuxCPP0904

-9.5 对象(二)

--LinuxCPP0905

-9.6 类与对象的成员(一)

--LinuxCPP0906

-9.7 类与对象的成员(二)

--LinuxCPP0907

-9.8 类与对象的成员(三)

--LinuxCPP0908

-9.9 继承(一)

--LinuxCPP0909

-9.10 继承(二)

--LinuxCPP0910

-9.11 继承(三)

--LinuxCPP0911

-9.12 多态(一)

--LinuxCPP0912

-9.13 多态(二)

--LinuxCPP0913

-9.14 编程实践

--LinuxCPP0914

-第九讲 类与对象--编程实践提交入口

第十讲 操作符重载

-10.1 提纲

--LinuxCPP1001

-10.2 四则运算符重载(一)

--LinuxCPP1002

-10.3 四则运算符重载(二)

--LinuxCPP1003

-10.4 关系与下标操作符重载

--LinuxCPP1004

-10.5 赋值操作符重载(一)

--LinuxCPP1005

-10.6 赋值操作符重载(二)

--LinuxCPP1006

-10.7 赋值操作符重载(三)

--LinuxCPP1007

-10.8 赋值操作符重载(四)

--LinuxCPP1008

-10.9 赋值操作符重载(五)

--LinuxCPP1009

-10.10 流操作符重载(一)

--LinuxCPP1010

-10.11 流操作符重载(二)

--LinuxCPP1011

-10.12 流操作符重载(三)

--LinuxCPP1012

-10.13 操作符重载总结

--LinuxCPP1013

-10.14 编程实践

--LinuxCPP1014

-第十讲 操作符重载--编程实践提交入口

第十一讲 泛型编程

-11.1 提纲

--LinuxCPP1101

-11.2 泛型编程概览

--LinuxCPP1102

-11.3 异常处理机制(一)

--LinuxCPP1103

-11.4 异常处理机制(二)

--LinuxCPP1104

-11.5 运行期型式信息(一)

--LinuxCPP1105

-11.6 运行期型式信息(二)

--LinuxCPP1106

-11.7 模板与型式参数化

--LinuxCPP1107

-11.8 题外话:术语翻译

--LinuxCPP1108

-11.9 泛型编程实践(一)

--LinuxCPP1109

-11.10 泛型编程实践(二)

--LinuxCPP1110

-11.11 泛型编程实践(三)

--LinuxCPP1111

-11.12 泛型编程实践(四)

--LinuxCPP1112

-11.13 泛型编程实践(五)

--LinuxCPP1113

-11.14 泛型编程实践(六)

--LinuxCPP1114

-11.15 泛型编程实践(七)

--LinuxCPP1115

-11.16 泛型编程实践(八)

--LinuxCPP1116

-11.17 泛型编程实践(九)

--LinuxCPP1117

-11.18 泛型编程实践(十)

--LinuxCPP1118

-11.19 编程实践

--LinuxCPP1119

-第十一讲 泛型编程--编程实践提交入口

第十二讲 Linux系统编程基础

-12.1 提纲

--LinuxCPP1201

-12.2 程序执行环境(一)

--LinuxCPP1202

-12.3 程序执行环境(二)

--LinuxCPP1203

-12.4 程序执行环境(三)

--LinuxCPP1204

-12.5 程序执行环境(四)

--LinuxCPP1205

-12.6 输入输出(一)

--LinuxCPP1206

-12.7 输入输出(二)

--LinuxCPP1207

-12.8 文件系统

--LinuxCPP1208

-12.9 设备

--LinuxCPP1209

-12.10 库(一)

--LinuxCPP1210

-12.11 库(二)

--LinuxCPP1211

-12.12 makefile文件(一)

--LinuxCPP1212

-12.13 makefile文件(二)

--LinuxCPP1213

-12.14 makefile文件(三)

--LinuxCPP1214

-12.15 编程实践

--LinuxCPP1215

-第十二讲 Linux系统编程基础--编程实践提交入口

第十三讲 进程编程

-13.01 提纲

--LinuxCPP1301

-13.02 进程基本概念

--LinuxCPP1302

-13.03 信号

--LinuxCPP1303

-13.04 进程管理(一)

--LinuxCPP1304

-13.05 进程管理(二)

--LinuxCPP1305

-13.06 进程管理(三)

--LinuxCPP1306

-13.07 进程间通信(一)

--LinuxCPP1307

-13.08 进程间通信(二)

--LinuxCPP1308

-13.09 进程间通信(三)

--LinuxCPP1309

-13.10 进程间通信(四)

--LinuxCPP1310

-13.11 进程池

--LinuxCPP1311

-13.12 编程实践

--LinuxCPP1312

-第十三讲 进程编程--编程实践提交入口

第十四讲 线程编程

-14.1 提纲

--LinuxCPP1401

-14.2 线程基本概念

--LinuxCPP1402

-14.3 线程管理(一)

--LinuxCPP1403

-14.4 线程管理(二)

--LinuxCPP1404

-14.5 线程管理(三)

--LinuxCPP1405

-14.6 线程管理(四)

--LinuxCPP1406

-14.7 线程同步机制(一)

--LinuxCPP1407

-14.8 线程同步机制(二)

--LinuxCPP1408

-14.9 C++11线程库(一)

--LinuxCPP1409

-14.10 C++11线程库(二)

--LinuxCPP1410

-14.11 C++11线程库(三)

--LinuxCPP1411

-14.12 C++11线程库(四)

--LinuxCPP1412

-14.13 C++11线程库(五)

--LinuxCPP1413

-14.14 编程实践

--LinuxCPP1414

-第十四讲 线程编程--编程实践提交入口

第十五讲 网络编程

-15.1 提纲

--LinuxCPP1501

-15.2 Internet网络协议

--LinuxCPP1502

-15.3 套接字(一)

--LinuxCPP1503

-15.4 套接字(二)

--LinuxCPP1504

-15.5 编程实践

--LinuxCPP1505

-第十五讲 网络编程--编程实践提交入口

课程文档

-课程PDF文件

LinuxCPP0811笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。