当前课程知识点:基于Linux的C++ >  第十一讲 泛型编程 >  11.10 泛型编程实践(二) >  LinuxCPP1110

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

LinuxCPP1110在线视频

LinuxCPP1110

下一节:LinuxCPP1111

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

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

我们来看这样一个例子

使用指针作为迭代器

你看它是怎么工作的

我们调用标准库里面的 find() 那个函数

来查找一个数组中的特定的元素

具体程序代码是这个样子

定义一个 size 这样一个常量

设它为 16

然后我开辟这样一个数组 a[size]

就表示 16 个元素的一个整数数组

我 for 循环把这个数组设定个值

然后我想查 key 这个值

在不在我们这个数组里

key 值一开始初始化成 7

find() 这个标准库里边的函数

它需要带三个参数

第一个参数是它的数组的首元素的基地址

第二个参数是这个数组的最后一个元素的

后一个元素的基地址

当然你说后一个元素不妥当

其实是这个数组的最后一个元素的

下一个存储位置的基地址

第三个就是你要查找的那个数据

这就是 find()

当然严格讲起来 find() 这个函数

它的前两个参数其实传的

当然不是数组的元素的基地址

而是两个迭代器

我们这里就使用这个指针作为迭代器

所以 find() 第一个参数传数组的基地址 写a

第二个参数传数组的最后一个元素的

下一个位置的地址编号

那个当然是 a+size

为啥 因为我们数组的

最后一个元素是 size-1 啊

0 号元开始嘛 所以过了 size-1

就是最后一个元素之后

那个存储空间的位置

才是 a 加size 我们传的是这个

这叫过尾元

同学们在使用标准库的时候

要特别注意这一条

它的所有的这样的迭代器

这样的容器元素的存储

都是使用过尾元的机制

这样的话 它的整个循环架构

它是一个半开半闭区间

左边是封闭的 右边是开的

所以有一个过尾的元素

它专门用它来判定这个数据的集

也就是我们容器中的元素是不是结束了的

你说为什么要这么去做呢

我们用结尾的方式不可以吗 可以是可以

但是有的时候有点小麻烦

更重要地 有的时候

我们可能想存储一个指针

我们没有办法用空指针

来作为这个容器的结尾标志

因为有的时候空指针也会作为元素存进去

它本身是有意义的

所以在这个时候

我们要想决定这个容器是不是结尾

要想判定这一点

那么使用过尾元其实是更方便的

除此之外 你就得定义一个无定义指针

来表示它的结尾标志 或者结尾指针

那还不如使用过尾元呢

这个模式操纵起来其实更方便

我们把 find() 这个函数返回值初始化给 ip

就是一个指向整数的指针

当 ip 结果是 a+size 的时候

也就是当 ip 指向这个过尾元的时候

说明我们没有找到对应的元素

因为如果找到了

find() 就会返回它所对应的

那个元素的基地址

所以你注意 find() 这个函数返回值

其实也是一个迭代器

它的返回值就是你要查找的

那个元素的基地址

所以如果 ip==a+size 说明我们没找到

我们输出这个信息就行了

否则 我们就输出我们找到了这个信息

指针作为迭代器

你看到我们调用 find() 函数

就是按照这样的模式进行工作的

接下来我们看向量如何工作

我们现在使用迭代器来操作向量

我们定义一个向量 这个例子里

我这个向量元素个数 我设成 10

vector〈int〉 iv(10)

10 个元素 还是初始设定

一个元素、一个元素给它赋上值

然后我们查找 key

key 值 仍然是 7

然后我们要定义 3 个迭代器变量

那个迭代器的类型叫什么呢

叫 vector〈int〉::iterator

这是向量迭代器的完整的类型的描述

这个类型是定义在 vector 那个类模板里面的

所以你要使用它的时候必须要用名解析

因为我们使用 int

是来体化我们这个向量模板的

所以这个类名是 vector〈int〉

解析“::iterator”

我们得到的就是这个迭代器

这就是完整的迭代器类型

在这个类型上 我定义变量 it

定义变量 head

把它初始化成 iv.begin()

定义变量 tail

把它初始化成 iv.end()

在向量这个类上

它提供了 begin() 和 end() 两个成员函数

begin() 获得这个向量的首元素的迭代器

end() 获得这个向量的过尾元的迭代器

这两个函数返回值都是迭代器

你就可以直接初始化为 head 和 tail

赋值也可以 就按照这个模式

然后我们调用 find()

传 head 传 tail 传 key

传指向零号元的迭代器

传指向过尾元的迭代器

传待查找的键值 key

返回值就是找没找到那个元素的时候

它返回那个迭代器

找到了返回找到元素的迭代器

没找着返回过尾元的对应的迭代器

所以我们把 find() 这个返回值赋值给 it

if( it != tail ) 说明我们找到了

否则我就没找着

做相应的处理就可以了

这个就是我们的向量迭代器

你看它和指针作为迭代器使用的方式

是不是非常非常类似

指针我们需要定义 int * ip 迭代器呢

我们需要定义 vector〈int〉::iterator it

必须按照这个方式来定义

从实现这个角度来讲

除了这两者之间的差别

其实其它(包括原理)都是类似的 对吧

这个就是标准模板库最强大的功能

它能够让你与指针一样的方式

来使用标准模板库里面的标准容器

这个是我们向量迭代器

当你不想通过这个迭代器

修改目标数据对象的值的时候

你定义这个迭代器

应该把它定义成常量

这个就叫常迭代器 或者叫迭代器常量

其实严格讲起来应该叫迭代器常量

你比如说讲 你可以这么定义:

const vector〈int〉::iterator it

那么在这个时候你想 *it 赋值为 10 就是错的

*it 可以引领 没错 这个没问题

但是因为 *it 本身是一个 const vector〈int〉出来的

它是一个 const

它的目标数据对象是个 const 是个常量

所以你可以引领

但是你不能把它赋值为另外一个值

这是不允许的

引领赋值给别人没问题

但是引领 要想赋值它就不成

这个就是常迭代器

迭代器可以和我们输入输出流一起工作

这个时候我们事实上

是将输入输出流作为容器的

听上去有点奇怪

但是输入输出流本身确实可以作为容器

因为它能够容纳数据

凡是能够容纳数据的

我们都可以称之为容器

它是按照这样的一个模式

那么在使用方式上

你需要定义流迭代器对象

你比如讲用 ostream_iterator〈int〉

可以用这个类来定义

一个输出流迭代器 oit(cout, "")

什么意思呢 这个意思就是

我要构造一个输出流迭代器

并且把这个输出流迭代器

和 cout 给挂接在一起

也就是说 我是把 cout 作为我们的输出流

每输出一个数据

中间都要用“”引起来的空格来分隔

这是我们输出流迭代器对象 oit

第二个例子是输入流

我们从 cin 里想获取数据

那么你就可以用 istream_iterator〈int〉

这个类来构造一个对象 iit( cin )

把它和 cin 挂接在一起

这样的话 这个数据流就是从 cin 里面来的

可以使用一个空指针创建流结束迭代器

什么意思呢

就是你可以构造一个不带参数的输入流的对象和输出流的对象

就是你可以构造一个不带参数的输入流的对象和输出流的对象

用它来作为流结束的标志

你比如说 istream_iterator〈int〉 iit

后面没有“()”

它就没有使用带参数的构造函数版本

它就使用无参数的构造版本

来构造一个空对象

它实际上就类似于空指针

我们就可以用它来代表

这个流结束的迭代器

相当于刚才那个向量迭代器的过尾元

需要说明的是

凡是可以出现迭代器参数的标准算法里

都可以使用我们的流迭代器

所以实际上标准算法和

我们输入输出流可以直接挂接的

操作起来肯定很方便

我们先看输出流迭代器的例子

在这里 我定义了两个常量

upper_bound 和 lower_bound

用来表达一个整数的范围

还是我们以前演示过的一个例子

我就随机生成一系列的整数

然后把它保存到向量里

然后我们对它进行输入输出

我们也可能是从输入流里直接获取数据

放到这个向量里 元素尺寸是 8 个

我实现了一个函数 Display()

它需要带两个参数

第一个参数是向量 第二个参数是字符串

我们首先输出这个字符串

然后我们定义一个整型向量的迭代器 head

然后再定义一个尾部迭代器 tail

head、tail 定义两个整型向量的迭代器

然后我们定义一个 oit 变量

让我们的输出流迭代器和 cout 输出流挂接在一起

让我们的输出流迭代器和 cout 输出流挂接在一起

中间用“;”分隔开

然后我们调用标准算法 copy() 将向量里的元素

一个接着一个地拷贝到我们的输出流里

每拷贝一个 插入一个分号

每拷贝一个 插入一个分号

就按照这个方式进行工作

你看 copy() 这个函数 它需要带三个参数

第一个是头指针 也就是头迭代器

第二个是尾迭代器

第三个是输出流迭代器

也就是说 copy() 这个函数

带三个参数全是迭代器

首元素在哪里 过尾元在哪里

这是前两个参数的意义

第三个参数就是这个流的目的地

想把这些元素拷哪去

指向它的原始位置 oit

指向它一开始的位置 就拷贝到这个位置

第二个元素接着继续往下拷贝

就按照这个方式

copy() 一个函数调用

就完成了所有的元素的拷贝

非常快吧 对于我们这道题来讲呢

它尤其特殊

因为我们输出流迭代器实际上

是和 cout 挂接在一起的

所以我们的数据向输出流里面一拷贝

结果就是把这个数据输出到屏幕上

拷贝一个 输出一个

拷贝一个 输出一个

拷贝一个 输出一个

中间是用逗号分隔开的

就按这个方式进行工作 很方便

基于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文件

LinuxCPP1110笔记与讨论

也许你还感兴趣的课程:

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