1.1 模板的概念
模板提高复用性,照片模板,PPT 模板,通用性强,并不是万能的。
模板的特点:
1. 模板不可以直接使用,它只是一个框架
2. 模板的通用性并不是万能的
1.2 函数模板
- C++ 另一种编程思想为泛型编程,主要利用的技术就是模板,提高复用性
- C++ 提供两种模板机制:函数模板和类模板
1.2.1 函数模板语法:
函数模板作用:
- 建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型 T 来代表
普通函数声明或定义:
void f(int a)
模板函数:
template <typename T>
void f(T a)
解释:
- template 英文是模板的意思,声明创建模板
- typename 数据类型,可以用 class 代替
- T 通用的数据类型,名称可以替换,通常为大写字母
总结
1. 函数模板利用关键字 template
2. 使用函数模板有两种方式:自动类型推导、显示指定类型
3. 模板的目的是为了提高复用性,将类型参数化
代码示例:
#include <bits/stdc++.h>
using namespace std;
void jhi(int &a,int &b) // 普通函数,参数 int 类型
{
int t = a;
a = b;
b = t;
}
void jhf(float &a,float &b) // 普通函数,参数 float 类型
{
float t = a;
a = b;
b = t;
}
// 函数模板
template <class T> // typename
void jh(T &a, T &b) // T 是一种通用类型,可以为 int float char 等
{
T t = a;
a = b;
b = t;
}
template <typename T> // typename
void f()
{
cout<<"Hello World!";
}
int main()
{
int a=1,b=2;
jhi(a,b);
cout<<a<<" "<<b<<endl;
float c=1.2,d=3.4;
jhf(c,d);
cout<<c<<" "<<d<<endl;
// 两种方式使用函数模板
// 1.自动类型推导
jh(a,b);
cout<<a<<" "<<b<<endl;
jh(c,d);
cout<<c<<" "<<d<<endl;
// 2. 显示指定类型
jh<int>(a,b);
cout<<a<<" "<<b<<endl;
// 1.自动类型推导,必须推导出一致的数据类型T,才可以使用
char c1 = 'c';
//jh(a,c1); // 自动类型推导,推不出来一致 T 的类型
// 2.模板必须要确定出 T 的数据类型,才可以使用
//f();
f<int>();
return 0;
}
1.2.2 函数模板注意事项:
注意事项:
- 自动类型推导,必须推导出一致的数据类型T,才可以使用
- 模板必须要确定出T的数据类型,才可以使用
总结:
- 使用模板时必须确定出通用数据类型 T,并能够推导出一致的类型
1.2.3 函数模板案例
案例描述:
- 利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序(类似上面交换的程序,数据类型可以变化)
代码示例:
#include <bits/stdc++.h>
using namespace std;
int a[110],n;
char c[110];
template <typename T>
void s(T *a)
{
for (int i=0; i<n-1; i++)
{
for (int j=i+1; j<n; j++)
if (a[j]<a[i])
swap(a[j],a[i]);
}
for (int i=0; i<n; i++)
cout<<a[i]<<" ";
}
int main()
{
cin>>n;
for (int i=0; i<n; i++)
cin>>a[i];
s(a);
for (int i=0; i<n; i++)
cin>>c[i];
s(c);
return 0;
}
1.2.4 普通函数与模板函数的区别:
- 普通函数调用时可以发生自动类型转换(隐式类型转换)
- 函数模板调用时,如果利用自动类型推到,不会发生隐式类型转换
- 如果利用显示类型指定的方式,可以发生隐式类型转换
代码示例
#include <bits/stdc++.h>
using namespace std;
int add1(int a,int b)
{
return a+b;
}
template <typename T>
int add2(T a,T b)
{
return a+b;
}
int main()
{
int a = 1;
char c = 'a';
cout<<add1(a,c)<<endl;
cout<<add2<int>(a,c);
return 0;
}
1.2.5 普通函数与模板函数的调用规则:
调用规则如下:
- 如果普通函数和函数模板都可以实现,优先调用普通函数
- 可以通过空模板参数列表来强制调用函数模板
- 函数模板也可以发生重载
- 如果函数模板可以产生更好的匹配,优先调用函数模板
代码示例:
#include <bits/stdc++.h>
using namespace std;
int add1(int a,int b)
{
cout<<"调用普通函数\n";
return a+b;
}
template <typename T>
int add1(T a, T b)
{
cout<<"调用模板函数\n";
return a+b;
}
template <typename T>
int add1(T a, T b, T c)
{
cout<<"调用模板函数\n";
return a+b;
}
int main()
{
int a = 1, b = 2;
cout<<add1(a,b)<<endl;
cout<<add1<>(a,b)<<endl;
cout<<add1(a,b,100)<<endl;
char c1 = 'a', c2 = 'b';
cout<<add1(c1,c2)<<endl;
return 0;
}
总结:
- 既然提供了函数模板,就不要提供普通函数了,容易产生二义性。
1.2.6 模板的局限性:
- 模板的通用性并不是万能的,
- 为了解决数组、或自定义类型提供模板的重载,提供具体化的模板