> 文档中心 > 【第12节 C++模板】

【第12节 C++模板】


函数模板

什么是模板: 把类型当做未知量,可以忽略类型影响

#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<<one<<endl;    cout<<two<<endl;}//typename 可以换成classtemplate void print(T a){    cout<<a<<endl;}

调用函数模板

  • ​ 隐式调用 : 正常的函数传参即可调用

    #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 随便改 ,就是类型代号_Ty Max(_Ty a, _Ty b){return a > b ? a : b;}int main(){  //隐式调用cout << Max(1, 2) << endl;cout << Max("string", "string")<<endl;cout << Max(1.1, 2.3 << endl;return 0;}
  • ​ 显示调用: 函数名(参数)

    #include#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 随便改 ,就是类型代号_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")<<endl;cout << Max(1.1, 2.3) << endl;//显示调用cout << Max("abc", "abd") << endl;print("string1", "string2");print("string1", 123);return 0;}

函数模板的两种形态

  • ​ 普通函数当做函数模板

  • ​ 类的成员函数是函数模板

    #include#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 随便改 ,就是类型代号_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")<<endl;cout << Max(1.1, 2.3) << endl;//显示调用cout << Max("abc", "abd") << endl;print("string1", "string2");print("string1", 123);//类照曝光额成员函数是函数模板MM mm;mm.print(123);mm.print("ILoveyou");mm.printData(12345);return 0;}

函数模板特殊的写法

  • ​ 缺省写法

    #include#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 随便改 ,就是类型代号_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")<<endl;cout << Max(1.1, 2.3) << endl;//显示调用cout << Max("abc", "abd") << endl;print("string1", "string2");print("string1", 123);//类照曝光额成员函数是函数模板MM mm;mm.print(123);mm.print("ILoveyou");mm.printData(12345);//模板函数可不可缺省return 0;}
  • ​ 存在常量类型

    #include#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 随便改 ,就是类型代号_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 size = 3;printArray(array);*/}int main(){  //隐式调用cout << Max(1, 2) << endl;cout << Max("string", "string")<<endl;cout << Max(1.1, 2.3) << endl;//显示调用cout << Max("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::print(){cout << "类模板" << endl;}template class Girl :public MM{public:Girl(string name) :MM(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::print(){cout << "类模板" << endl;}template class Girl :public MM{public:Girl(string name) :MM(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::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#includeusing 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& mm) const{return this->age > mm.age;}protected:string name;int age;};template void print(_Ty one){//错误1error C2679: 二进制“<<”: 没有找到接受“std::string”类型的右操作数的运算符(或没有可接受的转换)c:\users\administrator\desktop\mycjiajiapro\consoleapplication11\consoleapplication11\源.cpp171ConsoleApplication11cout << one << endl;}template _Ty Max(_Ty a, _Ty b){//错误5error C2784: “bool std::operator >(const std::reverse_iterator &,const std::reverse_iterator &)”: 未能从“MM”为“const std::reverse_iterator &”推导 模板 参数c:\users\administrator\desktop\mycjiajiapro\consoleapplication11\consoleapplication11\源.cpp371ConsoleApplication11return 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& 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* next) :data(data), next(next) {}_Ty getData() {return data;}Node* getNext(){return next;}protected:_Ty data;Node* next;//正常写法:Node* next;};template class List {public:List() {headNode = nullptr;}void insertList(_Ty data) {headNode = new Node(data, headNode);}void printList(){Node* pmove = headNode;while (pmove != nullptr) {//error C2679: 二进制“<<”: 没有找到接受“_Ty”类型的右操作数的运算符(或没有可接受的转换)cout <getData() <getNext();}cout << endl;}protected:Node* 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类型是:MMData<MM, MM>data(MM("小芳", 18), MM(89, 56));data.print();//上面两行 等效下面四行代码MM mmData("小芳", 18);MM mmScore(89, 56);Data<MM, MM> mData(mmData, mmScore);mData.print();}template void print(_Ty data){cout << data << endl;}int main(){//隐式调用print(MM("小芳", 32));//显示调用//类型:MMprint<MM>(MM("小美", 238));//起别名简化代码using MMType = MM;print(MMType("小美", 238));testFunc();return 0;}

函数模板重载

模板和普通函数 ,调用函数函数类型一致情况 优先调用普通函数

两个模板同时成立,优先调用类型相似度高的那个

类模板特化

局部特化

完全特化