C++学习笔记之模板(1)——从函数重载到函数模板
一、函数重载
因为函数重载比较容易理解,并且非常有助于我们理解函数模板的意义,所以这里我们先来用一个经典的例子展示为什么要使用函数重载,这比读文字定义有效的多。
现在我们编写一个交换两个int变量值得函数,可以这样写:
void swap(int & a, int & b)
{
int tmp; tmp = a;
a = b;
b = tmp; }
假如我们现在想在与上面函数相同的文件中(可以理解为同一个main函数中)交换两个float变量呢,是不是需要重新整一个函数名,重新定义一个函数呢?当然是不需要!
可以直接这样写:
#include <iostream> void swap(int & a, int & b);
void swap(float & a, float & b); int main()
{
using namespace std; int wallet1 = ;
int wallet2 = ;
float wallet3 = 125.33;
float wallet4 = 235.82; cout << "Before swapping wallet1 and wallet2:" << endl;
cout << "wallet1 = $" << wallet1 << endl;
cout << "wallet2 = $" << wallet2 << endl;
swap(wallet1, wallet2);
cout << "After swapping wallet1 and wallet2:" << endl;
cout << "wallet1 = $" << wallet1 << endl;
cout << "wallet2 = $" << wallet2 << endl; cout << "Before swapping wallet3 and wallet3:" << endl;
cout << "wallet3 = $" << wallet3 << endl;
cout << "wallet4 = $" << wallet4 << endl;
swap(wallet3, wallet4);
cout << "After swapping wallet3 and wallet4:" << endl;
cout << "wallet3 = $" << wallet3 << endl;
cout << "wallet4 = $" << wallet4 << endl; return ;
} void swap(int & a, int & b)
{
int tmp; tmp = a;
a = b;
b = tmp; } void swap(float & a, float & b)
{
float tmp; tmp = a;
a = b;
b = tmp; }
执行结果如下:

由此可以总结出函数重载的相关知识:函数重载就是允许存在多个同名的函数,但是函数的参数列表必须不同,即参数的类型或者数目不一样。如示例中的swap()函数有两个,但是输入的参数类型不一样,编译器就是根据参数列表(也称为函数特征)的不同来确定到底选择哪一个函数去执行!这样我们就可以为相同的操作,但是参数类型不同的函数只用同一个函数名,如示例中都是交换操作,只是参数类型不同而已。虽然函数重载很吸引人,但是很明显看出代码量比较大,所以不要滥用,仅当函数基本上执行相同的任务,但使用不同形式的数据时,才应采用函数重载……
试想一下,我们要交换char, int, short, double, float ...等等这许多变量,如果按照上述方式,正常人都疯了,于是函数模板款款而来……
二、函数模板
首先不说函数模板的定义,待洒家展示一下函数模板的神奇之处先,还是以事实说话,用函数模板实现上述功能:交换两个变量!
#include <iostream> template <typename T>
void Swap(T &a, T &b); int main()
{
using namespace std; int wallet1 = ;
int wallet2 = ;
cout << "Before swapping wallet1 and wallet2:" << endl;
cout << "wallet1 = $" << wallet1 << endl;
cout << "wallet2 = $" << wallet2 << endl;
Swap(wallet1, wallet2);
cout << "After swapping wallet1 and wallet2:" << endl;
cout << "wallet1 = $" << wallet1 << endl;
cout << "wallet2 = $" << wallet2 << endl; double wallet3 = 125.33;
double wallet4 = 235.82;
cout << "Before swapping wallet3 and wallet3:" << endl;
cout << "wallet3 = $" << wallet3 << endl;
cout << "wallet4 = $" << wallet4 << endl;
Swap(wallet3, wallet4);
cout << "After swapping wallet3 and wallet4:" << endl;
cout << "wallet3 = $" << wallet3 << endl;
cout << "wallet4 = $" << wallet4 << endl; char x = 'a';
char y = 'b';
cout << "Before swapping x and y:" << endl;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
Swap(x, y);
cout << "After swapping wallet3 and wallet4:" << endl;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
return ;
} template <typename T>
void Swap(T &a, T &b)
{
T tmp;
tmp = a;
a = b;
b = tmp;
}
执行如下:

这里我们实现了int, double, char类型的交换(但是其他任何类型的两个变量的交换均可实现,有兴趣的同学可以自己试一试,很简单,声明两个变量,调用一下函数就是了),但是可以看到,模板函数的定义就只是这么一小段:
template <typename T>
void Swap(T &a, T &b)
{
T tmp;
tmp = a;
a = b;
b = tmp;
}
好了,来好好解释一下,缓解同志们迫不及待的心情,嘿嘿……
所谓函数模板,就是让我们编写的函数独立于参数类型,只要函数执行的操作不变,就不用改变代码。函数模板以任意类型的方式来定义函数,以上面的Swap()模板函数为例:第一行指出要建立一个模板,类型为T,关键字template声明这是一个模板,关键字typename声明类型(有些老版本编译器不支持typename,用关键字class代替也一样),这里T是一个标志符,习惯上都用T(当然可以是S,Q,ABC等其他合法标识符),这个T代表着一种类型,但是具体代表什么类型(int?double?char?)是根据编译时输入的参数确定的,如上述main()函数的10,11,15行,编译器发现输入参数是int类型,那么T具体化为int, 同样第30,31,35,T就被具体化为char. 后面的代码就是交换两个变量的值。
要注意的是,函数模板本身并不是函数,它只是告诉编译器如何定义函数(这就是称之为模板的原因,提供一个框架而已),具体的函数是在编译过程中生成的。需要交换int的函数时,编译器按照模板的模式创建这样的函数,用int代替T,即函数是在编译过程中生成的,函数模板并不创建函数,只是创建一个模板去告诉编译器如何生成函数而已,最终的代码(编译之后)不包含任何模板,而只包含了为具体程序生成的实际函数。使用模板的好处是,它使得生成多个函数定义更简单、可靠。
专业一点的表述是,函数模板是通用的函数描述(ps:因为适合任何类型的参数),它们使用泛型来定义函数(ps:T可以带便任何类型),其中泛型可以用具体的类型(如int或者double)替换。通过将类型作为参数传递给模板,可是编译器生成该类型的函数。由于模板允许以泛型(刚刚ps中解释了泛型的感性理解哈)的方式编写程序,因此有时也被称为通用编程。由于类型是用参数表示的,因此模板特性也被称为参数化类型(parameterized types).
C++学习笔记之模板(1)——从函数重载到函数模板的更多相关文章
- 小猪猪C++笔记基础篇(六)参数传递、函数重载、函数指针、调试帮助
小猪猪C++笔记基础篇(六) ————参数传递.函数重载.函数指针.调试帮助 关键词:参数传递.函数重载.函数指针.调试帮助 因为一些事情以及自己的懒惰,大概有一个星期没有继续读书了,已经不行了,赶紧 ...
- C++函数重载和函数模板
1.函数重载 这是小菜鸟写的一个例子. 函数重载应该注意以下几点: 1.1重载函数有类似的功能: 1.2只能以参数的类型(形参个数和类型)来重载函数, int max(int a,int b);flo ...
- C++ 函数重载,函数模板和函数模板重载,选择哪一个?
重载解析 在C++中,对于函数重载.函数模板和函数模板重载,C++需要有一个良好的策略,去选择调用哪一个函数定义(尤其是多个参数时),这个过程称为重载解析. (这个过程将会非常复杂,但愿不要遇到一定要 ...
- C++ 函数重载与函数匹配
<C++ Primer>笔记,整理关于函数重载与函数匹配的笔记. 函数重载 void func(int a); //原函数 void func(double a); //正确:形参类型不同 ...
- C++中函数重载和函数覆盖的区别
C++中经常会用到函数的重载和覆盖,二者也在很多场合都拿出来进行比较,这里我就对二者的区别做点总结: 函数重载: 函数重载指的是函数名相同.函数特征值不同的一些函数,这里函数的特征值指的是函数的参数的 ...
- C++ 函数的扩展④--函数重载与函数指针
//函数扩展--函数重载与函数指针 #include<iostream> using namespace std; //函数参数类型不同 void Fuc(char * b){ print ...
- 位运算+引用+const+new/delete+内联函数、函数重载、函数缺省参数
update 2014-05-17 一.位运算 应用: 1.判断某一位是否为1 2.只改变其中某一位,而保持其它位都不变 位运算操作: 1.& 按位与(双目): 将某变量中的某些位(与0位与) ...
- c++中的函数重载、函数重写、函数重定义
目录 一.函数重载 二.函数重写 三.函数重定义 为了更加深刻的理解 函数重载.重写.重定义,我们可以带着如下这两个问题去思考: 1.子类中是否可以定义父类中的同名成员?为什么? 可以,因为子类与父类 ...
- C++学习笔记47:链表的概念与结点类模板
学堂在线学习笔记 链表的概念与结点类模板 顺序访问的线性群体--链表类 链表是一种动态数据结构,可以用来表示顺序访问的线性群体: 链表是由系列结点组成,结点可以在运行时动态生成: 每一个结点包括数据域 ...
随机推荐
- struct 与 typedef struct
1. 基本解释 typedef为C语言的关键字,作用是为一种数据类型定义一个新名字.这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等). 在编程中使用typede ...
- Android圆形图片--ImageView
[ RoundImageView.java ] package com.dxd.roundimageview; import android.content.Context; import andro ...
- CMDB反思4
CMDB模型设计2 http://blog.vsharing.com/xqscool/A1275233.html 估计大家看到破子的这两篇都有点晕哈,我也有点晕. 两篇对比来看. 第1处,属性部分 ...
- sql server 2008 r2 出问题
1.想利用sql2008的数据挖掘功能,以为是没有安装全,所以就卸载了. (1)利用Windows Installer Clean UP将以前的卸载干净 (2)出现了Could not open ke ...
- 常用SQL整理
整理了日常用到的一些sqls 1.插入表 insert into table_B select * from table_A 2.清空表 truncate table test #清空表,结构还存在d ...
- echart图表控件配置入门(一)
现在主流的web图表控件主要有hightchart.fusionchart.echart: echart作为百度前端部门近期推出的一个基于html5的免费图表控件,以其丰富图表类型和良好的兼容性速度得 ...
- 指定的值不是类型“Edm.Int32”的实例
指定的值不是类型“Edm.Int32”的实例参数名: value 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常 ...
- Android SDK无法更新解决方法
我这里主要说的是mac下如何设置Android SDK更新,windows下类似 首先说明为什么要这么麻烦,没办法身处在大天朝中,伟大的防火墙,苦逼的程序猿想要查点资料都是非常难的.不废话了,下面进入 ...
- Linux下的sort排序命令详解(一)
1 sort的工作原理 sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出. [zookeeper@master rh]$ cat ...
- tryparse的用法,^0*[1-9]\d*$
Entry entry = new Entry(); Int32 iParam; if(Int32.TryParse(entry.ajh,out iParam)) { /*如果转换成功就输出iPara ...