c++之模板

目录

一、函数模板

1、函数模板的格式

2、函数模板用法举例

二、类模板

1、类模板的格式

2、类模板用法举例


在C++中涉及了一个新知识———模板

关于模板,它是代码复用的手段,是泛型编程的基础

这里会介绍函数模板和类模板两种

一、函数模板

函数模板在使用时被参数化,是根据实参类型而产生函数的模板

1、函数模板的格式

template <typename T......>template <class T......>

其中template是关键字

typename和class是在尖括号里书写的格式,typename和class二者在大部分情况下没有区别,所以我们一般两种选择一种用即可,但是不能一个函数模板中两种都出现,只出现一种就好

T是类型名字,可以随便取,一般习惯以大写字母命名,T代表是一个模板类型(虚拟类型)

2、函数模板用法举例

在C语言中,我们要交换a和b两个数的值,需要自己写一个函数进行交换,如图:

 这种情况是最常见的,两个int类型的变量交换数据,那么如果下面继续交换两个double类型的变量呢,是不是又需要写一个Swapd是进行double类型变量交换的函数,那如果又交换char类型的呢?这样C语言就要重复多次写功能完全类似的函数,比较繁琐,而C++中的模板可以完美的解决这个问题

并且C语言交换还需要取地址,也会麻烦些,C++也有与之相对应的知识——引用来更方便清楚地进行Swap函数的运用(引用相关知识后面的博客会补上)

比如说main函数中,我们要交换几组不同的变量,如图:

 在这里我们就用上面所强调的格式进行函数模板的书写:

比如说main函数中,我们要交换几组不同的变量,如图:

 当写好函数模板后,代码运行时编译器会进行两步操作:模板参数推演和推演参数实例化

模板参数推演:根据main函数中需要交换的两个变量类型推演出T的类型

推演参数实例化:根据推演出的类型,程序内部形成新的Swap函数

当程序走到Swap(p,q)时,程序内部会形成如下图所示类似的函数:

当然剩下的double类型也一样,这里也说明了很重要的一点——每次执行Swap功能时并不是一直调用同一个函数,而是不断地根据模板参数进行推演,然后进行推演参数实例化

对于上面所写的交换函数swap,我们以后用的时候也不用自己写,库里面有swap函数,可以直接用(在std命名空间中)

下面对于另一种情况的讨论,我们换一个带返回值的函数进行研究,即:

返回值T的类型是根据n1和n2推演出来的,正常情况没什么问题,但是会有一种特殊情况是:传入Add的两个实参类型都不相同,例如一个int一个double,如图:

这时像上面这样的模板函数就有问题了,传入两个不同类型的值,T不能正确推演出返回值类型,对于这种情况有以下两种处理方法:

①、隐式实例化,编译器自动推演

改写成如下的样子:

 第一个(double)a,将a强制类型转化成double类型,即编译器认为a变为了3.0,那么编译器在推演T类型时就不会有矛盾,a、b都认为是double类型,所以输出值就是5.0+3.5=8.5

第二个和第一个类似,只不过是将3.5强转为int类型,编译器认为是b是3,输出值就是3+5=8

②、显式实例化

 大家可以观察一下结果,两种方式都是相同的

第一种我们没有干预编译器的推演,第二种是我们直接干预了T的类型,一般第二种用的比较多,方便并且可读性也高

在一般情况下如果返回值是T,并且所传的参数无法推演出T类型,例如上面所举例的Add函数的情形,那么我们就需要显示实例化,即第二种方法实现
但是有人会问,像上面这种例子,模板加两个参数一个T1,一个T2不是就可以了,这样在某些情况下又会产生新的问题,比如说:在template后面加了两个类型名,T1和T2

 在Add函数中,返回的是l+r,当操作符两边的类型不同时,会整型提升,int会转换为double

Add(1,5)两个相同类型,没有任何影响,答案是1+5=6

Add(1.1,5)中,T1代表double,T2代表int,在return时,提升为了double类型,即1.1+5.0=6.1,返回类型T1是double,所以答案为6.1

Add(1,5.5)中,T1代表int,T2代表double,在return时,同样提升为了double类型,即1.0+5.5=6.5,而返回类型T1是int,所以答案又变为了6

同时在运行代码时,也会报一个警告:

 最后再说明一点,当代码中既存在自己写的Add函数,又存在模板函数Add,这时候会参数匹配,如果原本的Add函数符合,就会调用原本的Add函数,当参数不匹配时,才会调用模板函数


二、类模板

类模板的用法和函数模板类似,在C++中类模板使用是非常多的

1、类模板的格式

template <typename T1, typename T2......>

class

{   ...   }

2、类模板用法举例

先举个例子,在学习C语言时,我们所写的栈(简易框架)是这样的:

 因为用的类型比较单一,所以可以直接typedef,那如果在我们的成员变量中,既要用int,又要用double,那靠C语言的知识就不是很方便的能够解决这种问题了,这时候类模板就上场了,如下在模拟实现Stack(简易框架)的代码可以观察类模板的使用:

 

像这样,就根本不用担心上面所说的多个类型的问题

另外,在使用类模板时,main函数中是必须要显示实例化的,如下所示:

需要注意的是,虽然Stack<int>,Stack<char>用的是相同的模板,但是是不同类型的呦

关于模板的用法在函数模板中详细讲解了,会熟练运用用函数模板的话,类模板也能很容易上手的

还有重要的一点:模板是不支持分离编译的

我们在完成项目时,都习惯声明放在.h,定义放在.cpp,但模板是不支持这样的

当然了,在不同文件中不能分离编译,在一个文件中是允许的

比如我们不想把函数void pop()当做内联函数处理,可能因为这个函数比较复杂

我们可以这样处理:

就可以很好解决这个问题啦! 

最后一个有意思的是,在C++中,函数可以有缺省参数,那么我们的模板当然也可以有,可以写成这种写法

我们给了一个T的缺省参数为char类型,这样我们不写具体类型编译器就会使用char类型的数据进行运行 

但是此时,我们想创建一个对象时,就必须要这样写才行:

在stack后加上尖括号,表示不传模板参数,就会用缺省参数了 



C++模板的相关知识就到这里啦


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值