目录
一、模板
二、函数模板
1. 函数模板
2.函数模板注意事项
3.函数模板案例
三、普通函数和模板函数的区别
四、普通函数和模板函数的调用规则
五、模板的局限性
模板的实用性很强,但不能完全完全复制使用
c++提供另一种编程思想 泛型编程 主要利用模板
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
模板是一种对类型进行参数化的工具;
通常有两种形式:函数模板和类模板;
函数模板针对仅参数类型不同的函数;
类模板针对仅数据成员和成员函数类型不同的类。
使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int 型,又可以实现double型的交换。模板可以应用于函数和类。
注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
语法:
template
// typename 也可以是 class 函数声明或定义
// 注释
template --- 声明创建模板
typename --- 表明其后面的符号是一种数据类型,可以用class代替
T --- 通用数据类型,名称可以替换,通常为大写字母
示例:
#include
using namespace std; // 函数模板 // 两个整形交换函数 void swp_int(int &a,int &b) { int temp = a; a=b; b=temp; } // 交换两个浮点型的函数 void swp_double(double &a,double &b) { double temp =a; a=b; b=temp; } // 函数模板 template // 声明一个模板,告诉编译器中紧跟着T不要报错 void my_Swap(T &a,T &b) { T temp =a; a=b; b=temp; } void test01() { int a=10; int b=20; cout<<"交换前 a = "< 运行结果:
总结:
- 函敌模板利用关键字template
- 使用函数模板有两种方式:自动类型推导、显示指定类型
- 模板的目的是为了提高复用性,将类型参数化
2.函数模板注意事项
注意事项
- 自动推导类型,必须推导出一致的数据类型T,才可以使用
- 模板必须要确定出T的数据类型,才可以使用
示例:
#include
using namespace std; // 注意事项 // 1. 自动推导类型,必须推导出一致的数据类型T,才可以使用 template // typename 可以替换成class void my_Swap(T &a,T &b) { T temp =a; a=b; b=temp; } void test01() { int a = 10; int b = 20; char c = 'c'; // 必须是一致的数据类型才能使用 // 如果一个是int一个是char则使用不了 cout<<"自动--模板函数--交换前 a = "<(); } int main() { test01(); test02(); return 0; }
运行结果:
3.函数模板案例
案例说明:
- 利用函数模板封装一个排序函数,可以对不同数据类型数组进行排序
- 排序规则从大到小,排序算法为选择排序
- 分别利用char数组和int数组进行测试
示例:
#include
using namespace std; // 交换的模板 template void func(T &a,T &b) { T temp =a; a=b; b=temp; } // 实现对数组的排序 template void Sort(T arr[],int len) { // 选择排序 for(int i=0;i void print_arr(T arr[],int len) { for(int i=0;i 运行结果:
三、普通函数和模板函数的区别
普通函数和函数模板的区别:
- 普通类型函数调用时可以发生自动类型转换(隐式类型转换)
- 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
- 如果利用显示指定类型的方式,可以发生隐式类型转换
示例:
#include
using namespace std; // 普通函数调用会发生隐式类型的转换 int add(int a,int b) { return a+b; } // 函数模板 template int my_ADD(T a,T b) { return a+b; } void test01() { int a=10; int b=20; char c='a'; // a=97 // 普通类型的函数会发生隐式类型转化 cout << "自动类型推导" << endl; cout< (a, c)) << endl; cout< (a,c)< 运行结果:
总结:建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T
四、普通函数和模板函数的调用规则
调用规则:
- 如果函数模板和普通函数都可以实现,优先调用普通函数
- 可以通过空模板参数列表强制调用函数模板
- 函数模板也可以重载
- 如果函数模板可以产生更好的匹配,优先调用函数模板
示例:
#include
using namespace std; void my_print(int a,int b) { cout<<"调用普通函数"< void my_print(T a,T b) { cout<<"模板函数调用"< void my_print(T a,T b,T c) { cout<<"重载--函数模板调用"< (a,b); // 3. 重载函数模板调用 my_print(a,b,100); // 4.如果函数模板可以产生更好的匹配,优先调用函数模板 char c1 = 'a'; char c2 = 'b'; cout << "更好的匹配" << endl; my_print(c1,c2); } int main() { test01(); return 0; } 运行结果:
五、模板的局限性
模板并不是万能的,有些特定数据类型,需要用具体化方式实现。
利用具体化的模板可以实现自定义类型的通用化
学习模板并不是为了写模板,而是在STL能够运用系统提供的模板
不支持数组之间的赋值操作
Template
void f(T a, T b)
{
a=b;
}
不支持自定义类型
提供重载函数的方式,可以为特定类型提供具体的模板
Template
void f(T a,T b)
{
if(a>b)
...
}
解决方法
示例:
#include
using namespace std; class person { public: person(string name,int age) { this->name=name; this->age=age; } string name; int age; }; // 对比两个数据是否相等 template bool my_compare(T &a,T &b) { if(a==b) return true; else return false; } // 利用具体化的对象实现,具体优化先调用 template<> bool my_compare(person &p1,person &p2) { if(p1.name==p2.name&&p1.age==p2.age) return true; else return false; } void test01() { int a = 10; int b =20; bool ret = my_compare(a,b); if(ret) cout<<"a==b"< 运行结果: