本阶段主要针对C++泛型编程和STL技术做详细讲解
模板就是建立通用的模具,大大提高复用性
举例子:
C++另一种编程思想成为泛型编程,主要利用的技术就是模板
C++提供两种模板机制:函数模板和类模板
语法如下:
代码:
1 #include<iostream> 2 using namespace std; 3 4 //函数模板 5 6 //交换两个整型函数 7 void swapInt(int &a, int &b) 8 { 9 int temp = a; 10 a = b; 11 b = temp; 12 } 13 14 //交换两个浮点型函数 15 void swapDouble(double &a, double &b) 16 { 17 double temp = a; 18 a = b; 19 b = temp; 20 } 21 22 //函数模板 23 template<typename T> //声明一个模板,告诉编译器 后面代码中紧跟着的T不要报错,T是一个通用数据类型 24 void mySwap(T &a, T &b) 25 { 26 T temp = a; 27 a = b; 28 b = temp; 29 } 30 31 32 void test01() 33 { 34 int a = 10; 35 int b = 20; 36 37 //swapInt(a, b); 38 //利用函数模板交换 39 //两种方式使用函数模板 40 //1、自动类型推导 41 //mySwap(a, b); 42 43 //2、显示指定类型 44 mySwap<int>(a, b); 45 46 cout << "a = " << a << endl; 47 cout << "b = " << b << endl; 48 49 double c = 1.1; 50 double d = 2.2; 51 swapDouble(c, d); 52 cout << "c = " << c << endl; 53 cout << "d = " << d << endl; 54 55 56 } 57 58 int main() 59 { 60 test01(); 61 62 //system("pause"); 63 return 0; 64 }
类型参数化,提高复用性
两种方法使用:自动类型推导,显示指定
注意事项:
自动类型推导,必须推导出已知的数据类型T才可以使用
模板必须确定出T的数据类型,才可以使用
利用函数模板实现一个排序函数,可以对不同数据类型数组进行排序
排序规则 从大到小, 排序算法 选择排序
分别利用char数组和int数组进行测试。
1 #include<iostream> 2 using namespace std; 3 4 //实现通用 对数组进行排序的函数 5 //规则 从大到小 6 //算法 选择排序 7 //测试 char 数组、 int 数组 8 9 //交换函数模板 10 template<class T> 11 void mySwap(T&a, T&b) 12 { 13 T temp = a; 14 a = b; 15 b = temp; 16 } 17 18 19 //排序算法 20 template<class T> 21 void mySort(T arr[], int len) 22 { 23 for (int i = 0; i < len; i++) 24 { 25 int max = i;//认定最大值的下标 26 for (int j = i + 1; j < len; j++) 27 { 28 //认定的最大值 比 遍历出的数值 要小,说明j下标的元素才是真正的最大值 29 if (arr[max] < arr[j]) 30 { 31 max = j;//更新最大值下标 32 } 33 } 34 if (max != i) 35 { 36 //交换max和i下标的元素,把最大的放到最前面去 37 mySwap(arr[max], arr[i]); 38 } 39 } 40 41 } 42 43 //提供打印数组模板 44 template<class T> 45 void printArray(T arr[], int len) 46 { 47 for (int i = 0; i < len; i++) 48 { 49 cout << arr[i] << " "; 50 } 51 cout << endl; 52 } 53 54 void test01() 55 { 56 //测试char数组 57 char charArr[] = "badcfe"; 58 int num = sizeof(charArr) / sizeof(char); 59 mySort(charArr, num); 60 printArray(charArr, num); 61 62 63 } 64 void test02() 65 { 66 //测试int数组 67 int intArr[] = { 7,5,1,3,9,2,4,6,8 }; 68 int num = sizeof(intArr) / sizeof(int); 69 mySort(intArr, num); 70 printArray(intArr, num); 71 } 72 73 int main() 74 { 75 //test01(); 76 test02(); 77 78 79 return 0; 80 }
普通函数调用时可以发生自动类型转换(隐式类型转换)
函数模板使用时,如果利用自动类型推导,不会发生隐式类型转换
如果利用显示指定类型的方式,可以发生隐式类型转换
1 #include<iostream> 2 using namespace std; 3 4 //普通函数与函数模板的区别 5 6 //1、普通函数在调用时可以发生隐式类型转换 7 //2、函数模板 用自动类型推导,不可以发生隐式类型转换 8 //3、函数模板 用显示指定类型,可以发生隐式类型转换 9 10 //普通函数 11 int myAdd01(int a, int b) 12 { 13 return a + b; 14 } 15 16 //函数模板 17 template<class T> 18 T myAdd02(T a, T b) 19 { 20 return a + b; 21 } 22 23 24 void test01() 25 { 26 int a = 10; 27 int b = 20; 28 29 char c = ‘c‘;// a = 97 c = 99 30 31 cout << myAdd01(a, c) << endl; 32 33 //自动类型推导 不会发生隐式类型转换 34 //cout << myAdd02(a, c)<< endl; 35 36 //显示指定类型 会发生隐式类型转换 37 cout << myAdd02<int>(a, c) << endl; 38 39 40 } 41 42 43 int main() 44 { 45 46 test01(); 47 48 49 return 0; 50 }
建议使用显示指定类型的方式,调用函数模板
调用规则:
1 #include<iostream> 2 using namespace std; 3 4 //普通函数与函数模板调用规则 5 //1、如果函数模板和普通函数都可以调用,优先调用普通函数 6 //2、可以通过空模板参数列表的方式 强制 调用 函数模板 7 //3、函数模板可以发生函数重载 8 //4、如果函数模板可以产生更好的匹配,优先调用函数模板 9 10 void myPrint(int a, int b) 11 { 12 cout << "调用的普通函数" << endl; 13 } 14 15 template<class T> 16 void myPrint(T a, T b) 17 { 18 cout << "调用的函数模板" << endl; 19 } 20 21 template<class T> 22 void myPrint(T a, T b, T c) 23 { 24 cout << "调用重载的函数模板" << endl; 25 } 26 27 void test01() 28 { 29 int a = 10; 30 int b = 20; 31 32 //myPrint(a, b); 33 34 //通过空模板参数列表,强制调用函数模板 35 //myPrint<>(a, b); 36 37 //myPrint(a, b, 100); 38 39 //如果函数模板产生更好的匹配,优先调用函数模板 40 char c1 = ‘a‘; 41 char c2 = ‘b‘; 42 myPrint(c1, c2); 43 } 44 45 46 int main() 47 { 48 test01(); 49 50 51 52 return 0; 53 }
既然提供了函数模板,最好不要提供普通函数,容易出现二义性。
1 #include<iostream> 2 using namespace std; 3 #include<string> 4 5 //模板的局限性 6 //模板并不是万能的,有些特定的数据类型,需要用具体化方式做特殊实现 7 8 class Person 9 { 10 public: 11 Person(string name, int age) 12 { 13 this->m_Name = name; 14 this->m_Age = age; 15 } 16 17 //姓名 18 string m_Name; 19 //年龄 20 int m_Age; 21 }; 22 23 //对比两个数据是否相等的函数 24 template<class T> 25 bool myCompare(T &a, T &b) 26 { 27 if (a == b) 28 { 29 return true; 30 } 31 else 32 { 33 return false; 34 } 35 36 } 37 38 39 //利用具体化的Person的版本实现代码,具体化优先调用 40 template<> bool myCompare(Person &p1, Person &p2) 41 { 42 if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age) 43 { 44 return true; 45 } 46 else 47 { 48 return false; 49 } 50 } 51 52 void test01() 53 { 54 int a = 10; 55 int b = 20; 56 bool ret = myCompare(a, b); 57 58 if (ret) 59 { 60 cout << "a == b" << endl; 61 } 62 else 63 { 64 cout << "a != b" << endl; 65 } 66 67 68 } 69 70 void test02() 71 { 72 Person p1("Tom", 10); 73 Person p2("Tom", 11); 74 75 bool ret = myCompare(p1, p2); 76 if (ret) 77 { 78 cout << "p1 == p2" << endl; 79 } 80 else 81 { 82 cout << "p1 != p2" << endl; 83 } 84 85 } 86 87 int main() 88 { 89 //test01(); 90 test02(); 91 92 93 94 return 0; 95 }
利用具体化模板,可以解决自定义类型通用化
学习模板并不是为了写模板,而是在STL中能够运用系统提供的模板
1 #include<iostream> 2 using namespace std; 3 #include<string> 4 5 //类模板 6 template<class NameType, class AgeType> 7 class Person 8 { 9 public: 10 Person(NameType name, AgeType age) 11 { 12 this->m_Name = name; 13 this->m_Age = age; 14 } 15 16 void showPerson() 17 { 18 cout << "name: " << this->m_Name 19 << "\t" 20 << "age: " << this->m_Age << endl; 21 } 22 23 NameType m_Name; 24 AgeType m_Age; 25 26 }; 27 28 void test01() 29 { 30 Person<string, int> p1("孙悟空", 999);//模板参数列表 和 实参 31 p1.showPerson(); 32 } 33 34 35 int main() 36 { 37 test01(); 38 39 40 41 return 0; 42 }
1.类模板没有自动类型推导
2.类模板在模板参数列表中可以有默认参数
1 #include<iostream> 2 using namespace std; 3 #include<string> 4 5 //类模板与函数模板的区别 6 template<class NameType, class AgeType = int> 7 class Person 8 { 9 public: 10 Person(NameType name, AgeType age) 11 { 12 this->m_Name = name; 13 this->m_Age = age; 14 } 15 16 void showPerson() 17 { 18 cout << "name: " << this->m_Name 19 <<"\t" 20 << "age = " << this->m_Age << endl; 21 } 22 23 24 NameType m_Name; 25 AgeType m_Age; 26 }; 27 28 //1、类模板没有自动类型推导的使用方式 29 void test01() 30 { 31 //Person p("孙悟空", 1000);//错误,无法用自动类型推导 32 33 Person<string> p("孙悟空", 1000);//正确,智能用显示指定类型 34 35 p.showPerson(); 36 } 37 //2、类模板在模板参数列表中可以有默认参数 38 void test02() 39 { 40 Person<string, int> p("猪八戒", 999); 41 p.showPerson(); 42 43 } 44 45 int main() 46 { 47 //test01(); 48 test02(); 49 50 51 return 0; 52 }
1 #include<iostream> 2 using namespace std; 3 4 //类模板中成员函数创建时机 5 //类模板中成员函数在调用时才去创建 6 class Person1 7 { 8 public: 9 void showPerson1() 10 { 11 cout << "Person1 show" << endl; 12 } 13 }; 14 15 class Person2 16 { 17 public: 18 void showPerson2() 19 { 20 cout << "Person2 show" << endl; 21 } 22 }; 23 24 template<class T> 25 class MyClass 26 { 27 public: 28 T obj; 29 30 //类模板中的成员函数 31 void func1() 32 { 33 obj.showPerson1(); 34 } 35 void func2() 36 { 37 obj.showPerson2(); 38 } 39 40 }; 41 42 43 void test01() 44 { 45 MyClass<Person2>m; 46 //m.func1(); 47 m.func2(); 48 } 49 50 int main() 51 { 52 test01(); 53 54 55 return 0; 56 }
类模板中的成员函数并不是一开始就能创建,而是在调用的时候才创建出来。
1 #include<iostream> 2 using namespace std; 3 #include<string> 4 5 //类模板对象做函数参数 6 template<class T1, class T2> 7 class Person 8 { 9 public: 10 Person(T1 name, T2 age) 11 { 12 this->m_Name = name; 13 this->m_Age = age; 14 } 15 16 void showPerson() 17 { 18 cout << "姓名: " << this->m_Name 19 <<"\t" 20 << "年龄: " << this->m_Age << endl; 21 } 22 23 T1 m_Name; 24 T2 m_Age; 25 }; 26 //1、指定传入类型 27 void printPerson1(Person<string, int> &p) 28 { 29 p.showPerson(); 30 } 31 32 void test01() 33 { 34 Person<string, int> p("孙悟空", 100); 35 36 printPerson1(p); 37 } 38 39 40 //2、参数模板化 41 template<class T1,class T2> 42 void printPerson2(Person<T1, T2> &p) 43 { 44 p.showPerson(); 45 cout << "T1的类型为: " << typeid(T1).name() << endl; 46 cout << "T2的类型为: " << typeid(T2).name() << endl; 47 48 } 49 50 void test02() 51 { 52 Person<string, int> p("猪八戒", 90); 53 54 printPerson2(p); 55 56 } 57 58 59 //3、整个类模板化 60 template<class T> 61 void printPerson3(T &p) 62 { 63 p.showPerson(); 64 cout << "T的数据类型为:" << typeid(T).name() << endl; 65 66 } 67 68 69 void test03() 70 { 71 Person<string, int> p("唐僧", 30); 72 printPerson3(p); 73 } 74 75 76 int main() 77 { 78 //test01(); 79 //test02(); 80 test03(); 81 82 83 return 0; 84 }
三种传递方式
实际开发中最常用的是 指定传入类型;
其他两种,实际上是函数模板配合类模板
原文:https://www.cnblogs.com/zlh-1024powr/p/14623154.html