C++ 函数模板初探

C++之所以强大,其中肯定少不了模板的功劳。使用好模板也可以为以后的编程省去很多的功夫。

函数模板是通用的函数描述,也就是说,它们使用泛型来定义函数,其中泛型可用具体的类型(如int或double) 替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。由于模板允许以泛型的方式编写程序,因此有时也被称为通用编程。由于类型使用参数表示的,因此模板特性有时也被成为参数化类型(parameterized types) (C++ Primer Plus 第六版中文 P281)

以上就是一个函数模板的定义。

首先如果没有函数模板, 试想如果需要一个函数来交换两个数字的值,这个时候由于不知道两个数字的类型,你需要使用函数重载来写很多个类型的函数,如

void Swap(int &, int &);
void Swap(double &, double &);
void Swap(char &, char &);
void Swap(short &, short &);
......

作为一个程序员怎么会容忍这么多相似度极高并且效率低下的事情发生呢? 于是模板就出现了。上面的类型只需要短短几行全部就可以搞定。

template <typename AnyType>
void Swap(AnyType &a, AnyType &b)
{
	AnyType temp;
	temp = a;
	a = b;
	b = temp;
}

其中typename这个关键字也可以使用class来代替。在标准C++98添加关键字typename之前,c++都是使用关键字class来创建模板。

这个模板可以把上面那么多行的函数全部都替换掉,是不是感觉就方便了许多。

但是万一我们想要交换两个数组怎么办,那之前这个模板就不管用了。别着急,c++的模板也支持重载

这意味着你可以像重载函数一样的重载你的模板,这样你的代码试用的范围就更加的广泛。

尽管模板很好用,但是还是有一些局限性。

template <class T>
int f(T a, T b)
{
	return a>b;
}

在这个代码中,加入比较的是结构体那么就不成立,如果是数组那可能结果就和你所预期的不一样。
为了解决这些问题,c++有两种解决方法。

1.c++允许重载运算符,这样的话就可以用于特定的结构体或者数组上
2.可以为特定类型提供具体化的模板定义。

那么这次我们就来讨论第二种解决方法。

假设定义了如下结构:

struct job
{
	char name[40];
	double salary;
	int floor;
}

假设我们想要使用上面的Swap模板来交换这个结构体。c++允许将一个结构体赋值给另一个结构体,因此这个Swap模板是可以使用,但是假如我们只想交换salary和floor成员,而不交换name成员怎么办,那么我们需要使用不同的代码。

然而c++第二个解决方法就是提供一个具体化函数定义----成为显示具体化(explicit specialization), 其中包含所需代码。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板。

template <typename T>
void Swap(T &, T &);
//这个是常规模板
template <> void Swap<int> (int &, int &);
//这个是具体化模板

1.对于给定的函数名,可以有非模板函数、模板函数、和显式具体化模板函数以及它们的重载版本
2.具体化模板是由于常规模板,而非模板函数由于具体化和常规模板。
3.显式具体化的原型和定义应以template<>打头,并通过名称来指出类型。
当然这个模板原型也可以这样写

template <> void Swap(int &, int&);

实例化和具体化

为了进一步了解模板,必须理解术语实例化和具体化。记住,在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板为特定类型生成函数定义时,得到的是模板实例(iinstantiation)。 例如函数调用Swap(i,j)导致编译器生成Swap()的一个实例,该实例使用int类型。模板并非函数定义,但是用int的模板实例是函数定义。这种实例化方式被称为隐式实例化(implicit instantiation)。

最初编译器只能通过隐式实例化,来使用模板生成的函数定义。但现在c++还允许显示实例化(explicit instantiation)。使用这种实例化的方式是:

template void Swap<int> (int &, int &);

实现这种特性的编译器看到上述声明后,会使用Swap()模板生成一个使用int类型的实例。也就是说,该声明的意思是“使用Swap()模板生成int类型的函数定义”

隐式实例化、显示实例化和显示具体化统称为具体化(specialization)。它们的相同之处在于,他们表示的都是使用具体类型的函数定义,而不是通用描述。

编译器选择使用哪个函数版本
对于函数重载、函数模板和函数模板重载,c++需要一个定义良好的策略,来决定为函数调用使用哪一个函数定义,尤其是有多个参数时。这个过程称为重载解析(overloading resolution)。大概过程如下
1. 创建候选函数列表。其中包含于被调用函数的名称相同的函数和模板函数。
2. 使用候选函数列表创建可行函数列表。这些都是参数数目正确的函数。
3. 确定是否有最佳的可行函数。如果有,则使用它,否则该函数调用出错。

以上就是函数模板的一个大概初探,深入的后面还会写到,希望大家都可以利用好模板这个强大的工具。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值