概念
通用性
复用性
差异性
函数模板
C++另一种编程思想是泛型编程,主要利用的技术就是模板
C++提供两种模板机制,函数模板和类模板
函数模板的语法
函数模板作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型代替。
语法:
template<typename T>
函数声明或定义
解释:
template —声明创建模板
typename —表面其后面的符号是一种数据类型,可以用class代替
T —通用模板的数据类型,名称可以替换,通常为大写字母
#include <iostream>
using namespace std;
//交换两个整型
void swapInt(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
//交换两个浮点型
void swapDouble(double &a, double &b) {
double temp = a;
a = b;
b = temp;
}
//函数模板
template <typename T>
void mySwap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
void example() {
int a = 1, b = 2;
double c = 1.1, d = 2.2;
//使用常规函数
swapInt(a, b);
swapDouble(c, d);
//第一种,通过自动类型推导的方式让编译器判断类型
mySwap(a, b);
//第二种,显式指定类型
mySwap<double>(c, d);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
cout << "d = " << d << endl;
}
int main() {
example();
return 0;
}
- 函数模板利用关键字 template
- 使用函数模板有两种方式:自动类型推导、显示指定类型
-
注意事项
自动类型推导,必须推导出一致的数据类型T才能使用。
- 模板必须要确定出T的数据类型,才可以使用。
```cpp
include
using namespace std; //交换两个整型
//注意事项: //1. 自动类型推导,必须推导出一致的数据类型T才可以使用 //2. 末班必须要确定出T的数据类型才可以使用 //交换两个浮点型
//函数模板
template
}
void example()
{
func
<a name="5yA7U"></a>
## 排序示例
不需要进行函数重载。
```cpp
#include <iostream>
using namespace std;
//实现一个通用排序函数
// 从大到小
// 选择排序
// 两种数据类型
template <typename T>
void myswap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
template <typename T>
void mySort(T arr[], int len) {
for (int i = 0; i < len; i++) {
int max = i;
for (int j = i + 1; j < len; j++) {
//认定的最大值比遍历出的数值要小,说明j下标的元素才是真正的最大值,做交换
if (arr[max] < arr[j]) {
max = j;
}
}
if (max != i) {
//交换逻辑
myswap(arr[max],arr[i]);
}
}
}
//打印数组的末班
template <typename T>
void printArray(T arr[], int len) {
for (int i = 0; i < len; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void example() {
char charArr[] = "bcaeifdgh";
int lens = sizeof(charArr) / sizeof(char);
mySort(charArr, lens);
printArray(charArr, lens);//会输出a-i的倒序
int numarr[] = { 5,3,6,9,8,6,1,5,4,2,3,5,5,1,0 };
lens = sizeof(numarr) / sizeof(int);
mySort(numarr, lens); //从大到小排序
printArray(numarr, lens);
}
int main() {
example();
return 0;
}
普通函数和函数模板的区别
- 普通函数调用时可以发生自动类型转换
- 函数末班调用时,如果利用自动类型推导,不会发生饮食类型转换
- 如果利用显示指定类型的方式,可以发生隐式类型转换。
建议使用制定类型的方式,调用函数模板,防止推导意外。template <typename T>
T add(T a, T b) {
return a + b;
}
void example() {
int a = 10, b = 20;
char c = 0;
cout << add(a, b); //不能进行隐式类型转换
// cout << add(a, c); //必须特定的类型
cout << add<int>(a, c); //可以进行隐式类型转换(强制转换)
}
普通函数和函数模板的调用规则
- 如果函数模板和普通函数都可以实现,优先调用普通函数
- 可以通过空模板参数列表来强制调用函数模板
- 函数模板可以发生重载
- 如果函数模板可以产生更好的匹配,优先调用函数模板 ```cpp
void myPrint(int a, int b) { //声明即存在。
cout << “调用普通函数” << endl;
}
template
如果提供了函数模板,则不要使用函数,如果使用函数,则不要使用模板。
<a name="nJIHS"></a>
# 模板的局限性
模板只能在部分情况简单算法可以,如果传入的是数组,对象等模板就无法通用。<br />**局限性:**
- 模板的通用性并不是万能的
**例如:**
```cpp
template<class T>
void f(T a, T b)
{
a = b;
}
在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了
再例如:
template<class T>
void f(T a, T b)
{
if(a > b) { ... }
}
在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行
因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板
class Person {
public:
Person(string name, int age) {
this->m_age = age;
this->m_name = name;
}
string m_name;
int m_age;
};
template <typename T>
bool myCompare(T &a, T &b) {
if (a == b)return true; //可以重载==号解决此问题。
else return false;
}
//利用具体化的Person版本实现代码,具体化会优先调用。
//如果不加template,则是普通的函数重载
template <> bool myCompare(Person &a, Person &b) { //具体化的代码
if (a.m_age == b.m_age && a.m_name == b.m_name) return true;
else return false;
}
void example() {
int a = 10;
int b = 20;
bool ret = myCompare(a, b);
if (ret)cout << "==" << endl;
else cout << "!=" << endl;
Person P1("Tom", 10);
Person P2("Tom", 10);
ret = myCompare(P1, P2);
if (ret)cout << "==" << endl;
else cout << "!=" << endl;
}