概念:建立通用的模具,提高复用性。。
特点:
● 模板不能被直接使用,他只是一个框架
● 模板是通用,但不是万能
C++中的一种编程思想称为泛型编程,主要利用的技术就是模板
C++提供两种模板机制:函数模板和类模板。
函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表。。。
语法:
写完模板声明后,后面就要跟着写函数的声明或者定义
template——声明创建模板
typename——表示其后面的符号是一种数据类型,可用class(类模板,当然可以都写class)代替
T——通用的数据类型,名称可替换,通常为大写字母
如:T func(T a)-->【参考void func(int a)】
案例引入:
发现逻辑相同,因此我们可以创建一个模板实现各种类型的数据交换。。
例子:
①创建模板
②采用模板实现:
1——自动类型推导(直接塞参数,编译器自动推导类型)
2——显示指定类型
其中中括号内的int是告诉编译器,用int替代T(即告知编译器数据类型)
函数模板的注意事项:
● 自动推导:必须推导出一致的数据类型T才可以使用。
● 模板必须要确定出T的数据类型才能使用。。
关于第一点(编译器推导不出一致的T类型):
关于第二点(编译器不知道你在干嘛):
第二点的解决办法(强制指定数据类型):
练手1:
用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序
排序规则为从大到小,算法为选择排序
采用char数组和int数组进行测试
1 #include <iostream> 2 3 using namespace std; 4 5 //从大到小,采用选择算法 6 7 template<class T> //交换数据函数模板 8 void mySwap(T &a, T &b){ 9 T temp = a; 10 a = b; 11 b = temp; 12 } 13 14 template<class T> //排序函数模板,采用选择算法 15 void mySort(T arr[], int len){ 16 for(int i = 0; i < len; i++){ 17 int max = i; //认定最大值的下标 18 for(int j = i + 1; j < len; j++){ //j = i + 1表示不用再从自身及前面已经排序好的数再进行比较 19 //认定的最大值比遍历的值要小,说明j下标的元素才是真正的最大值 20 if(arr[max] < arr[j]){ 21 max = j; //更新最大值下标 22 } 23 } 24 if(max != i){ 25 //交换下标为max和i的元素 26 mySwap(arr[max], arr[i]); 27 } 28 } 29 } 30 31 template<class T> //打印数组模板 32 void printArray(T arr[], int len){ 33 for (int i = 0; i < len; i++){ 34 cout << arr[i] << " "; 35 } 36 cout << endl; 37 } 38 ///////////////////////////////////////////////////// 39 void test01(){ 40 //char数组 41 char charArr[] = "badcfehiz"; 42 int num = sizeof(charArr) / sizeof(char); 43 mySort(charArr, num); 44 printArray(charArr, num); 45 } 46 47 void test02(){ 48 //int数组 49 int intArr[] = {8,5,9,2,4,1,35,15,94,100}; 50 int num = sizeof(intArr) / sizeof(int); 51 mySort(intArr, num); 52 printArray(intArr, num); 53 } 54 55 int main(){ 56 test01(); 57 test02(); 58 system("pause"); 59 return 0; 60 }
普通函数和函数模板的区别(是否存在自动类型转换,也叫隐式类型转换):
● 普通函数调用时可以发生自动类型转换(隐式类型转换)
● 函数模板调用时,若采用自动类型推导,则不会发生隐式类型转换
● 如果采用显示指定类型的方式,可以发生隐式类型转换
例子(别忘了在main函数中调用test函数):
①此处把c的char类型变量自动转换成int类型的c(ASCII码),再进行计算:
②模板自动推导不能采用自动类型转换(编译器没法给你统一化):
③显示指定类型(此处指定了int类型)可以存在自动类型转换:
普通函数与函数模板调用规则(问题来源于普通函数和函数模板能够重名)
1.如果函数模板和普通函数都可以实现,优先调用普通函数
2.可以通过空模板参数列表来强制用函数模板
3.函数模板也可以发生重载
4.如果函数模板可以产生更好的匹配,优先调用函数模板
1.①如果普通函数只是个声明,而函数模板有完整的实现,那么编译器依旧会调用普通函数,并且给你报错。。
2.①空模板强制调用语法:函数名<void>(参数列表);
如:
3.①函数模板也能发生重载:
4.①
此时主函数体内调用:
我们知道,普通函数存在隐式类型转换(ASII码),此时这俩个模板编译器都可以调用。。
但是普通函数还需要把char类型自动转换为int类型,编译器嫌麻烦,不如直接用模板替换成char类型更快。。
因此,这类情况下编译器会优先调用模板函数。。
模板的局限性
● 切记,模板的通用性不是万能的,部分特定的数据类型需要用具体化方式做实现。。
例如(当我们往这个模板传递一个数组的时候,就不能实现了):
想要实现自定义的数据类型进行某些处理(比如赋值,比较大小等),C++有两种方法可以实现:
1.运算符重载(操作多的时候很麻烦)
2.提供具体化的目标重载模板函数(运行时会优先调用)
关于第二点的例子:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Person{ 6 public: 7 Person(string name, int age){ 8 this->m_name = name; 9 this->m_age = age; 10 } 11 string m_name; 12 int m_age; 13 }; 14 15 template<class T> 16 bool myCompare(T &a, T &b){ 17 if(a == b){ 18 return true; 19 } 20 else{ 21 return false; 22 } 23 } 24 25 template<> bool myCompare(Person &a, Person &b){ //具体化实现Person,具体化会被优先调用 26 if(a.m_name == b.m_name && a.m_age == b.m_age){ 27 return true; 28 } 29 else{ 30 return false; 31 } 32 } 33 34 void test1(){ 35 int a = 10; 36 int b = 10; 37 bool ret = myCompare(a,b); 38 if(ret){ 39 cout << "两者相等" << endl; 40 } 41 else{ 42 cout << "两者不相等" << endl; 43 } 44 } 45 46 void test2(){ 47 Person p1("Tom",11); 48 Person p2("Tom",12); 49 50 bool ret = myCompare(p1,p2); 51 if(ret){ 52 cout << "两者相等" << endl; 53 } 54 else{ 55 cout << "两者不相等" << endl; 56 } 57 } 58 59 int main(){ 60 test1(); 61 test2(); 62 system("pause"); 63 return 0; 64 }
学习目标不是为了写目标,是为了咱们后面在STL能够白嫖系统的代码。。
标签:类型转换,函数,int,数据类型,编译器,模板 From: https://www.cnblogs.com/MorningMaple/p/16909721.html