概念
通用性
复用性
差异性
函数模板
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 />**局限性:**- 模板的通用性并不是万能的**例如:**```cpptemplate<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;}
