模板

目录

一:引入

二:函数模板

1.概念

2.格式

3.示例

4.实例化

<1>: 隐式实例化

<2>: 显式实例化

5.参数的匹配原则

三:类模板

1.格式

2.实例化


一:引入

我们通常写交换函数的时候,可以使用函数重载的方式来实现不同类型的交换函数,如下述示例:

#include<iostream>
using namespace std;
void Swap(int& x, int& y)
{
	int tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
}
void Swap(double& x, double& y)
{
	double tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
}
void Swap(char& x, char& y)
{
	char tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	int a = 1, b = 2;
	Swap(a, b);
	cout << a << " " << b << endl;
	double c = 1.1, d = 2.2;
	Swap(c, d);
	cout << c << " " << d << endl;
	return 0;
}

 运行效果为:

07623424a5e14416b82636d5275ca017.png

但是,当有一个新的类型出现时,需要我们自己添加对应的函数,代码可维护性降低,还可能会出现一个出错所有的重载均出错的情况。 ---> 引入函数模板

二:函数模板

1.概念

       函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

2.格式

typename是用来定义模板参数关键字,也可以使用class。
 
template<class T>
template<class T1, class T2>

template<typename T>
template<typename T1, typename T2>

 那么引入示例的模板函数可以写做:

template<class T>
void Swap(T& x, T& y)
{
    T tmp = 0;
    tmp = x;
    x = y;
    y = tmp;
}

此时,编译器用模板实例化生成的 Swap 函数。

3.示例

示例代码:

#include<iostream>
using namespace std;
template<class T>
void Swap(T& x, T& y)
{
	T tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	int a = 1, b = 2;
	Swap(a, b);
	cout << a << " " << b << endl;
	double c = 1.1, d = 2.2;
	Swap(c, d);
	cout << c << " " << d << endl;
	return 0;
}

 运行效果为:

8eeeb76aedb642cab68891bacf7014b1.png

 在此处,调用的两次 Swap 函数是否为同一个函数???

我们对上述代码进行调试:

918431c1d1044e7fb68217f40265026a.png

4848d235b57f46d6a962caee6b5e5cc5.png 

我们发现两次 Swap 函数调用了不同的函数。

4.实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。
模板参数实例化分为:隐式实例化和显式实例化。

<1>: 隐式实例化


隐式实例化 --- 让编译器根据实参推演模板参数的实际类

示例:

#include<iostream>
using namespace std;
template<class T>

T Add(T& x, T& y)
{
	return x + y;
}

int main()
{
	int a = 1, b = 2;
	cout << Add(a, b) << endl;
	double c = 1.1, d = 2.2;
	cout << Add(c, d) << endl;
	return 0;
}

 运行效果为:

9acdd5c3fd2b498cb77405f404087e76.png

那如果, Add 函数中两个参数类型不匹配会产生什么样的现象,通过下述代码,观察现象:

int main()
{
	int a = 1, b = 2;
	double c = 1.1, d = 2.2;
	cout << Add(a, d) << endl;
	return 0;
}

 运行效果为:

c57ef930b91042638e1bf11ab5c63842.png

当编译器在实例化时,参数 a 为 int 类型,参数 d 为 double 类型,但模板参数列表中的类型必须为同一类型,所以编译器无法判断其为 int 类型还是 double 类型而报错(在模板中,编译器一般不会进行类型转换操作)。


 解决上述问题的方法:

(1): 用户自己来强制转化

83feccd8e5ea42ae90563a59c6bf3351.png

解决方法:

在引用形参前面加上const 

C++对引用的 const 做了优化,它会创建临时变量,让引用指向临时变量。

e405d489e66d42a1841ab94077d5f11f.png

(2): 使用显式实例化


<2>: 显式实例化


显式实例化 --- 在函数名后的<>中指定模板参数的实际类型


#include<iostream>
using namespace std;
template<class T>
//T Add(T& x, T& y)
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = 1, b = 2;
	double c = 1.1, d = 2.2;
	cout << Add<int>(a, d) << endl;
	cout << Add<double>(a, d) << endl;
	return 0;
}

 不加 const 运行效果:

c9879330a6474b5e8241e3505cf0c5aa.png

 加 const 运行效果为:  

147a9f9ee7714b16b418e3f17561020c.png

5.参数的匹配原则


  • 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
示例代码:
 
#include<iostream>
using namespace std;
// 专门处理int的加法函数
int Add(int x, int y)
{
	return x + y;
}
// 通用加法函数
template<class T>
T Add(T x, T y)
{
	return x + y;
}
int main()
{
	cout << Add(1, 2) << endl; // 与非模板函数匹配,编译器不需要特化
	cout << Add<int>(1, 2) << endl; // 调用编译器特化的Add版本

	return 0;
}
通过调试,查看两次调用的函数是否为同一个函数:
 
47cb5810bb9d41b8afda3c853a042d26.png

 Add(1,2) 调用了非模板函数。

bbc1f9ad6bfe44558eb4ddbac32f63e0.png
 Add<int>(1,2) 调用了模板函数。
 
  • 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。

示例代码:

#include<iostream>
using namespace std;
// 专门处理int的加法函数
int Add(int x, int y)
{
	return x + y;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}
int main()
{
	cout << Add(1, 2) << endl; //与非函数模板类型完全匹配,不需要函数模板实例化
	cout << Add(1, 2.0) << endl; //模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数

	return 0;
}

 通过调试,查看两次调用的函数:

42530c796e1b44f1b2d556b488abc756.png

 Add(1,2) 调用了非模板函数。

65134599041b4d66bb5839cb489042b7.png

Add(1,2.0) 调用了模板函数。

  • 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

三:类模板

1.格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
 // 类内成员定义
};

2.实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的
类型放在<> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
 
//示例
// Vector  类名
//Vector<int>  类型
Vector<int> s1;
Vector<double> s2;

17cc33a22fc1484287f24a951f942961.jpeg

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值