什么是模板: 把类型当做未知量,可以忽略类型影响
#includeusing namespace std; int Max(int a, int b) { return a > b ? a : b; } string Max(string a, string b) { return a > b ? a : b; } //引入模板这个东西 template //告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty Max(_Ty a, _Ty b) { return a > b ? a : b; } int main() { return 0; }
声明模板的语法
//单个未知类型 template//告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号 Ty Max(_Ty a, _Ty b) { return a > b ? a : b; } //可以多个未知类型 template void print(_Ty1 one ,_Ty2 two) { cout< void print(T a) { cout<
调用函数模板
-
隐式调用 : 正常的函数传参即可调用
#include
using namespace std; int Max(int a, int b) { return a > b ? a : b; } string Max(string a, string b) { return a > b ? a : b; } //引入模板这个东西 template //告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号 _Ty Max(_Ty a, _Ty b) { return a > b ? a : b; } int main() { //隐式调用 cout << Max(1, 2) << endl; cout << Max("string", "string")< -
显示调用: 函数名<类型名>(参数)
#include
#include using namespace std; int Max(int a, int b) { return a > b ? a : b; } string Max(string a, string b) { return a > b ? a : b; } //引入模板这个东西 template //告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号 _Ty Max(_Ty a, _Ty b) { return a > b ? a : b; } //_Ty =string a="abc" b="abc" template void print(_Ty1 one ,_Ty2 two) { cout << one << endl; cout << two << endl; } int main() { //隐式调用 cout << Max(1, 2) << endl; cout << Max("string", "string")< ("abc", "abd") << endl; print ("string1", "string2"); print ("string1", 123); return 0; }
函数模板的两种形态
-
普通函数当做函数模板
-
类的成员函数是函数模板
#include
#include using namespace std; int Max(int a, int b) { return a > b ? a : b; } string Max(string a, string b) { return a > b ? a : b; } //引入模板这个东西 template //告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号 _Ty Max(_Ty a, _Ty b) { return a > b ? a : b; } //_Ty =string a="abc" b="abc" template void print(_Ty1 one ,_Ty2 two) { cout << one << endl; cout << two << endl; } class MM { public: template void print(_Ty data) { cout << data << endl; } template void printData(_Ty data); protected: string name; int age; }; //在类外实现的时候不能省略template这一块 template void MM::printData(_Ty data) { cout << data << endl; } int main() { //隐式调用 cout << Max(1, 2) << endl; cout << Max("string", "string")< ("abc", "abd") << endl; print ("string1", "string2"); print ("string1", 123); //类照曝光额成员函数是函数模板 MM mm; mm.print(123); mm.print ("ILoveyou"); mm.printData(12345); return 0; }
函数模板特殊的写法
-
缺省写法
#include
#include using namespace std; int Max(int a, int b) { return a > b ? a : b; } string Max(string a, string b) { return a > b ? a : b; } //引入模板这个东西 template //告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号 _Ty Max(_Ty a, _Ty b) { return a > b ? a : b; } //_Ty =string a="abc" b="abc" template void print(_Ty1 one ,_Ty2 two) { cout << one << endl; cout << two << endl; } class MM { public: template void print(_Ty data) { cout << data << endl; } template void printData(_Ty data); protected: string name; int age; }; //在类外实现的时候不能省略template这一块 template void MM::printData(_Ty data) { cout << data << endl; } template void printData(_Ty1 one, _Ty2 two) { cout << one << "t" << two << endl; } void testFunc() { printData("string", 1234); //函数模板的缺省,显示调用,可以不用传类型,但是参数是不能少的 printData ("ILoveyou", 1234); } int main() { //隐式调用 cout << Max(1, 2) << endl; cout << Max("string", "string")< ("abc", "abd") << endl; print ("string1", "string2"); print ("string1", 123); //类照曝光额成员函数是函数模板 MM mm; mm.print(123); mm.print ("ILoveyou"); mm.printData(12345); //模板函数可不可缺省 return 0; } -
存在常量类型
#include
#include using namespace std; int Max(int a, int b) { return a > b ? a : b; } string Max(string a, string b) { return a > b ? a : b; } //引入模板这个东西 template //告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号 _Ty Max(_Ty a, _Ty b) { return a > b ? a : b; } //_Ty =string a="abc" b="abc" template void print(_Ty1 one ,_Ty2 two) { cout << one << endl; cout << two << endl; } class MM { public: template void print(_Ty data) { cout << data << endl; } template void printData(_Ty data); protected: string name; int age; }; //在类外实现的时候不能省略template这一块 template void MM::printData(_Ty data) { cout << data << endl; } template void printData(_Ty1 one, _Ty2 two) { cout << one << "t" << two << endl; } //存在传常量写法 //size_t:unsigned int 的别名 template void printArray(_Ty1 array)//_Ty1 = int* size=3 { for (int i = 0; i < size; i++) { cout << array[i]; } cout << endl; } void testFunc() { printData("string", 1234); //函数模板的缺省,显示调用,可以不用传类型,但是参数是不能少的 printData ("ILoveyou", 1234); int array[3] = { 1, 2, 3 }; //没有做缺省必须显示调用 printArray (array); //做了缺省可以隐式调用 printArray(array); //不能传入变量,只能传入常量,函数模板如果存在变量的情况下 } int main() { //隐式调用 cout << Max(1, 2) << endl; cout << Max("string", "string")< ("abc", "abd") << endl; print ("string1", "string2"); print ("string1", 123); //类照曝光额成员函数是函数模板 MM mm; mm.print(123); mm.print ("ILoveyou"); mm.printData(12345); //模板函数可不可缺省 return 0; }
如何生成一个类模板
templateclass MM { public: protected: } //只要被template修饰就是一个模板类,用没用未知类型没有关系
类模板调用
-
必须采用显式调用
#include
using namespace std; //template <> //class Data //{ // //}; template class MM { public: protected: }; int main() { //必须采用显示调用 MM mm; MM mm2; MM mm3; //MM mm;错误的! return 0; } -
类模板不是一个实际类型,所以所有用到类名的地方都需要使用: 类名<未知类型> 方式使用
#include
using namespace std; //template <> //class Data //{ // //}; template class MM { public: MM(){}; MM(string name):name(name){} void print(); protected: string name; }; //在类外实现 template void MM<_Ty>::print() { cout << "类模板" << endl; } template class Girl :public MM<_Ty> { public: Girl(string name) :MM<_Ty>(name) { } protected: }; int main() { //必须采用显示调用 MM mm; MM mm2; MM mm3; //MM mm;错误的! Girl girl("Loveyou"); girl.print(); return 0; } -
多文件中,类模板 中的声明和实现一定在一起的,不能分开写。
#include
using namespace std; //template <> //class Data //{ // //}; template class MM { public: MM(){}; MM(string name):name(name){} void print(); protected: string name; }; //在类外实现 template void MM<_Ty>::print() { cout << "类模板" << endl; } template class Girl :public MM<_Ty> { public: Girl(string name) :MM<_Ty>(name) { } protected: }; template class Data { public: Data(_Ty1 one, _Ty2 two) :one(one), two(two){} void print(); protected: _Ty1 one; _Ty2 two; }; template void Data<_Ty1, _Ty2>::print() { cout << one << endl; cout << two << endl; } int main() { //必须采用显示调用 MM mm; MM mm2; MM mm3; //MM mm;错误的! Girl girl("Loveyou"); girl.print(); Data mmInfo("小芳",19); mmInfo.print(); Data data(12, 10); data.print(); return 0; }
基本自定义类型
自定义类型也是一个模板
模板传入自定义类型,关键点就在于重载运算符
#include#include using namespace std; class MM { public: MM(string name, int age) :name(name), age(age){} friend ostream& operator<<(ostream& out, MM& mm) { out << mm.name << " " << mm.age; return out; } bool operator>(MM& mm) const { return this->age > mm.age; } protected: string name; int age; }; template void print(_Ty one) { //错误 1 error C2679: 二进制“<<”: 没有找到接受“std::string”类型的右操作数的运算符(或没有可接受的转换) c:usersadministratordesktopmycjiajiaproconsoleapplication11consoleapplication11源.cpp 17 1 ConsoleApplication11 cout << one << endl; } template _Ty Max(_Ty a, _Ty b) { //错误 5 error C2784: “bool std::operator >(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)”: 未能从“MM”为“const std::reverse_iterator<_RanIt> &”推导 模板 参数 c:usersadministratordesktopmycjiajiaproconsoleapplication11consoleapplication11源.cpp 37 1 ConsoleApplication11 return a > b ? a : b; } int main() { //函数模板传入自定义类型 print(12); print ("string"); print(MM("mm", 19)); MM xiaoF("小芳", 18); MM xiaoL("小丽", 28); MM result = Max (xiaoF, xiaoL); //MM result = Max(xiaoF, xiaoL);函数模板可以隐式调用 cout << result << endl; return 0; }
#include模板嵌套using namespace std; class MM { public: MM(string name, int age) :name(name), age(age) {} friend ostream& operator<<(ostream& out, const MM& mm) { out << mm.name << " " << mm.age; return out; } bool operator>(MM& mm) const { return this->age > mm.age; } protected: string name; int age; }; template void print(_Ty one) { //error C2679: 二进制“<<”: 没有找到接受“_Ty”类型的右操作数的运算符(或没有可接受的转换) cout << one << endl; } template _Ty Max(_Ty a, _Ty b) { //rror C2676: 二进制“>”:“_Ty”不定义该运算符或到预定义运算符可接收的类型的转换 return a > b ? a : b; } template class Node { public: Node(_Ty data, Node<_Ty>* next) :data(data), next(next) {} _Ty getData() { return data; } Node<_Ty>* getNext() { return next; } protected: _Ty data; Node<_Ty>* next; //正常写法:Node* next; }; template class List { public: List() { headNode = nullptr; } void insertList(_Ty data) { headNode = new Node<_Ty>(data, headNode); } void printList() { Node<_Ty>* pmove = headNode; while (pmove != nullptr) { //error C2679: 二进制“<<”: 没有找到接受“_Ty”类型的右操作数的运算符(或没有可接受的转换) cout << pmove->getData() << endl; pmove = pmove->getNext(); } cout << endl; } protected: Node<_Ty>* headNode; }; void testList() { List list; list.insertList(1); list.insertList(2); list.insertList(3); list.printList(); List mmList; mmList.insertList(MM("小芳", 18)); mmList.insertList(MM("小丽", 28)); mmList.insertList(MM("小美", 38)); mmList.printList(); } int main() { //函数模板传入自定义类型 print(12); print ("string"); print(MM("mm", 19)); MM xiaoF("小芳", 18); MM xiaoL("小丽", 28); MM result = Max (xiaoF, xiaoL); //MM result = Max(xiaoF, xiaoL); 函数模板可以隐式调用 cout << result << endl; testList(); return 0; }
明白类型是什么即可,适当可以借用using语法起别名 简化代码
#include函数模板重载using namespace std; template class MM { public: MM(_Ty1 one, _Ty2 two) :one(one), two(two) {} friend ostream& operator<<(ostream& out, const MM& mm) { out << mm.one << " " << mm.two; return out; } protected: _Ty1 one; _Ty2 two; }; template class Data { public: Data(_Ty1 one, _Ty2 two) :one(one), two(two) {} void print() { cout << one << " " << two << endl; } protected: _Ty1 one; _Ty2 two; }; void testFunc() { //_Ty1类型是:MM //_Ty2类型是:MM Data , MM > data(MM ("小芳", 18), MM (89, 56)); data.print(); //上面两行 等效下面四行代码 MM mmData("小芳", 18); MM mmScore(89, 56); Data , MM > mData(mmData, mmScore); mData.print(); } template void print(_Ty data) { cout << data << endl; } int main() { //隐式调用 print(MM ("小芳", 32)); //显示调用 //类型:MM >(MM ("小美", 238)); //起别名简化代码 using MMType = MM (MMType("小美", 238)); testFunc(); return 0; }
模板和普通函数 ,调用函数函数类型一致情况 优先调用普通函数
两个模板同时成立,优先调用类型相似度高的那个
类模板特化局部特化
完全特化



