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

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

LinuxCPP1112在线视频

LinuxCPP1112

下一节:LinuxCPP1113

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

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

接下来我们讨论怎么设计自己的模板

首先从函数模板开始

函数模板的最主要的目的

是为了设计通用的函数

以适应广泛的数据型式

基本定义格式是这样的

template〈模板型式参数列表〉

后者跟着是函数返回值类型、函数的名称、函数的参数列表

后者跟着是函数返回值类型、函数的名称、函数的参数列表

就是在整个函数的前边

加上template〈模板型式参数列表〉

对于函数原型来讲就应该这么写

template〈classT 〉void Swap( T & a, T & b )

如果是函数实现你就 “{}” 后面跟着函数体就完了

如果是函数实现你就 “{}” 后面跟着函数体就完了

都按照这个模式

class 这个关键字和 typename 是一模一样的

我前面不讲了吗

在这个地方用 class 也行 用 typename 也行

推荐使用 typename

函数模板的体化和特化 有一些需要说明的

函数模板的体化和特化 有一些需要说明的

针对于特定型的参数

在声明和第一次调用的时候

这个模板才会被体化

也就是说 函数体化是在它声明和第一次调用的时候进行的 这是一个

也就是说 函数体化是在它声明和第一次调用的时候进行的 这是一个

第二个 每次体化

它都形成针对特定型参数的重载函数版本

对于一个型 T1

它会生成一个体化的函数

对于一个型 T2

它会生成一个体化的函数

这两个函数显然是不一样的

因为它们的型不一样

这是两个重载的函数 特别注意这一点

第三个 文件最终只保留特定型参数的一份体化版本

第三个 文件最终只保留特定型参数的一份体化版本

如果对于同一个型

实际上你生成了好多个体化版本的函数

那么最终它保留其中的一份就够了

多余的没必要 这是第三个

第四个 显式体化主要用于库的设计

你可以做显式体化

但是这种东西主要是用于库设计的

还有你可以做显式的特化

显式特化会覆盖体化的同样的版本

对于同型的那样的函体

如果已经有了一个体化的版

后来你又做了特化的版

那特化版就会覆盖那个体化的版

它不会去调用那个体化的

如果它先看到了特化

甚至它连体化那个版本都不会去做了

就是直接调用你特化那个版本

去执行就完了

那我们看这样一个例子

对于一个函数模板

基本的声明格式和定义的格式就是这个样子

基本的声明格式和定义的格式就是这个样子

如果你想显式地体化它

那么你可以有两种方式

一 使用显式的长整型模板参数来体化这个函数 f() 这是可以的

一 使用显式的长整型模板参数来体化这个函数 f() 这是可以的

前面加一个 template 关键字

就表示它是一个显式的体化

后面没有 “〈〉” 的

所以这就是一个显式体化

只有一个 template 关键字

你想让编译器自动去推导这个函数的版本

那么你可以不写这个 “〈〉”

第二种方式

它会利用 d 的型来推导这个函数模板

它的模板实际参数应该是什么型

它的模板实际参数应该是什么型

这一样是显式体化

显式特化和体化是不一样的

template那个关键字后边

会有一个 “〈〉”

里面什么东西都没有的 “〈〉”

这个就叫显式特化

我们这个里边使用显式的整型参数来做显式特化

我们这个里边使用显式的整型参数来做显式特化

你同样地可以让编译器去自动地推导这个函数的模板实际参数型

你同样地可以让编译器去自动地推导这个函数的模板实际参数型

第二个 “〈〉”里面不写 可以

但是 template〈〉 那个不能省了

那是显式特化的标志

只有 template 那是显式体化

不是显式特化

有 template〈〉 里面还带着东西——typename 的

有 template〈〉 里面还带着东西——typename 的

那个就是模板

它既不是体化也不是特化

我们看这样一个例子

这个是我们的交换函数 Swap()

带两个参数 都是两个引用

因为我想交换两个数据对象的值嘛

这两个数据对象的型被我们参数化 写在模板参数里

这两个数据对象的型被我们参数化 写在模板参数里

template〈class T 〉void Swap( T & a, T & b )

返回值是个 void

两个参数的型就是 T &、T &

都是对那个 T 型的引用

函数里就可以使用那个模板参数的型

就相当于那个型已知一样

去写你的程序代码

具体实现很简单 三步互换

这个没什么可说的

我们看怎么用

我定义两个量 m、n

然后定义俩字符量 a 和 b

定义两个 double 量 c 和 d

我们可以 Swap( m, n )

像普通函数一样调用 Swap()

括号里传两个参数 m、n

这是一个正确调用 它会体化 Swap()

它就会根据函数模板

来体化一个 Swap() 函数

体化后的这个函数将会是什么样子呢

它将会接受两个整型引用的参数

因为你传的是 m 和 n

它发现可以把 T 替换成 int 完成这个调用

它发现可以把 T 替换成 int 完成这个调用

那么它就会体化这个 Swap( int &, int & )

然后形成这个调用

体化这个 把这个 T 全都换成 int 形成一个函数

体化这个 把这个 T 全都换成 int 形成一个函数

然后调用形成后的这个函数

它是正确体化的

第二个 Swap〈char〉( m, n )

你想把它当成一个字符来调用

行不行呢 行

因为正常情况下

m 和 n 本身的型是整数

所以如果你要体化它

它就会体化整数版本

但是你在这里边用一个〈char〉

指明让它体化 char 版本

它的意思就是用 char 来替代这个函数模板中的 T

它的意思就是用 char 来替代这个函数模板中的 T

生成一个 Swap() 函数

这个地方就会调用生成的那个函数

所以它体化的将是 Swap( char &, cha r& ) 这个函数

所以它体化的将是 Swap( char &, cha r& ) 这个函数

然后我们调用的就是这个函数

第三个 Swap〈double〉( c, d )

这也没问题

你传一个 double 进去

就表示这个 T 型是 double

它就给你生成一个 double 版本的 Swap()

然后调用它 这是我们的交换函数

你看函数模板的实现和使用

看上去实际上是相当直接的

接下来的一个重要概念就是函子

我们要同学们写一个函数

求某个数据集的最小元

元素类型是什么呢 是 T

也就是说什么类型都有可能

那么你怎么解决这个问题

我要你写一个抽象的算法

那么有一种实现策略

就是使用函数指针作为回调函数参数

我们讲数据抽象与程序抽象的时候

特别谈到过 我们要使用一个函数指针作为我们那个函数的回调函数参数

特别谈到过 我们要使用一个函数指针作为我们那个函数的回调函数参数

用它来完成具体的数据的操作

这样的话 我们写的原来那个函数才是一个抽象的算法 抽象的函数

这样的话 我们写的原来那个函数才是一个抽象的算法 抽象的函数

就这个意思 所以这道题本身仍然可以使用函数指针

就这个意思 所以这道题本身仍然可以使用函数指针

作为我们的回调函数参数来进行编程

这是第一种实现策略

第二种实现策略呢

就是使用我们现在要讲的函子来作为回调函数的参数

就是使用我们现在要讲的函子来作为回调函数的参数

我们首先来看函数指针实现

template〈typename T〉

Min() 函数本身

返回值是一个 const T &

接受的三个参数 一个是 const T * a

指向这个数据集的基地址

一个 int n 表示元素的个数

还有一个 comparer

这个比较函数 传的三个参数

我们内部实现

首先把索引定义成 0

然后写一个 for 循环

调用 comparer那个函数指针

所指向的比较函数进行两个元素的比较

返回较小的那一个

for 循环里记录最小元的索引

最后返回那个最小元 就可以了

你看这个里面

模板起到了非常重要的作用

T 型被我们抽取出来作为模板的参数

从而保证了我们所写的这段代码

可以适应广泛的型式

不管这个 T 型是什么

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

LinuxCPP1112笔记与讨论

也许你还感兴趣的课程:

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