内容纲要
167讲 模板的概念、基本语法、注意实现数组排序、普通函数与函数模板的区别
- 该阶段属于C++ 提高编程。
- 本阶段主要针对C++ 泛型编程和STL 技术做详细讲解,提高C++更深层次的使用
模板
模板就是简历通用的模具,大大提高复用性
- 模板不可以直接使用,他只是一个框架
- 模板的通用并不是万能的
函数模板
- C++ 另一种编程思想称为
泛型编程
,主要利用的技术就是模板 - C++ 提供两种模板机制:函数模板 和 类模板
使用方法如下代码。
#include <iostream>
#include "string"
using namespace std;
//函数模板
template<typename T>
void mySwap(T &a,T &b) {
T temp = a;
a = b;
b = temp;
}
void main() {
int a = 10;
int b = 20;
//函数模板有两种使用方法
//1.自动类型推导
//mySwap(b, a);
//2.显示指定类型
mySwap<int>(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
Summary
- 函数模板利用关键字 template
- 使用函数模板有两种方式:1、自动类型推导 2、显示指定类型
- 模板的目的是为了提高复用性,将类型参数化
函数模板注意事项
注意事项:
- 自动类型推导,必须推导出一致的数据类型 T,才可以使用
- 模板必须确定 T 的数据类型, 才可以使用。
1,当类型不同时,自动类型推导推不出一致的数据类型T,编译器报错
2,当未指定T的类型时,编译器亦会报错。需要在<>中显示写入指定的数据类型。
函数模板案例---选择排序。
案例描述:
-
利用函数模板封装一个排序函数,可以对 不同数据类型数组 进行排序
-
排序规则从大到小,排序算法为选择排序
-
分别利用char 数组 和 int数组 进行测试。
代码如下
#include<iostream>
#include"string"
using namespace std;
/*
案例描述:
- 利用函数模板封装一个排序函数,可以对 不同数据类型数组 进行排序
- 排序规则从大到小,排序算法为选择排序
- 分别利用char 数组 和 int数组 进行测试。
*/
template<typename T>
void swap(T &a, T &b) {
T temprary = a;
a = b;
b = temprary;
}
template<class T>
void printArr(T arr[]) {
for (size_t i = 0; i < 6; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
template<typename T>
void selectSort(T arr[],int length) {
for (size_t i = 0; i < length; i++)
{
int max = i;
for (size_t j = i +1; j < length; j++)
{
if (arr[j] > arr[max]) { //选最大的。
max = j;
}
}
//swap(arr[i], arr[max]);//交换认定的最大值。
T fortemp = arr[i];
arr[i] = arr[max];
arr[max] = fortemp;
}
}
void test() {
char test[] = "abcdef";
int abc[] = { 1,3,5,2,35,75 };
int length = sizeof(test)/sizeof(test[0]); //最好在外面算出它的大小,如果在里面计算的话,通过值拷贝可能会出问题。
selectSort(test,length);
printArr(test);
}
void main() {
test();
}
普通函数和模板函数的区别
普通函数与函数模板的区别:
- 普通函数调用时可以发生自动类型转换(隐式类型转换)
- 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
- 如果利用显示指定类型的方式,可以发生隐式类型转换(说人话:看下面的
myAdd02<int>(a,c);
)
#include <iostream>
#include "string"
using namespace std;
/*
- 普通函数调用时可以发生自动类型转换(隐式类型转换)
- 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
- 如果利用显示指定类型的方式,可以发生隐式类型转换(说人话:)
*/
int myAdd01(int a, int b) {
return a + b;
}
template <typename T>
T myAdd02(T a, T b) {
return a + b;
}
void test() {
int a = 10;
int b = 20;
char c = 'c';
cout << myAdd01(a, c);
//cout << myAdd02(a, c);//自动类型推导。不会发生隐式类型转换。
cout << myAdd02<int>(a, c);//显示指定类型,会发生隐式类型转换,char -> int;
}
void main() {
test();
}
Summary
建议使用显示指定类型的方式。调用函数模板,因为自己可以知道要用什么类型的T !!!
普通函数和函数模板的调用规则
- 通过空模板参数列表,强制调用函数模板
总结:既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性。。
模板的局限性
- 模板的通用性不是万能的,就像之前数组排序中我写得传入类,它就不能进行自定义数据类型的匹配。。在用于数组的匹配时也会出现一些局限性。
- 处理自定义数据类型用模板来实现目前有 2种 方法:
- 重载所需要的运算符(但是很麻烦,每个运算符都重载太麻烦了)
- 重载模板 语法:
template<> T myCompare(T &p1,T &p2){ }
Summary
- 利用具体化的模板,可以解决自定义类型的通用化
- 学习模板并不是为了写模板!!!而是在STL能够运用系统提供的模板。。!!!
TIP: STL ( Standard Template Library ) 标准模板库