cpp提供两种模板机制 函数模板和类模板
函数模板 基本语法建立一个通用的函数,返回值类型和形参类型不具体制定,用虚拟类型来代表
语法:
template
typename:表明后面符号是一种数据类型
T:通用数据类型,可替换
例:不同类型的相加
#includeusing namespace std; template //告诉编译器后面的T不要报错,是个通用的数据类型 void m_swap(T &a,T &b){ int temp=a; a=b; b=temp; } template void print_ab(T a,T b){ cout<<"a:"< 对于模板函数调用
//自动推导 m_swap(a,b); //显示指定类型 m_swap案例(a,b); #include#include #include #define random(x) rand()%(x) using namespace std; template void mySwap(T &a,T &b){ int temp=a; a=b; b=temp; } template //告诉编译器后面的T不要报错,是个通用的数据类型 //升序选择排序 void mySort(T a[],int len){ for(int i=0;i a[j]){ min=j; } } if(min!=i){ swap(a[i],a[min]); } } } template void print_arr(T a,int len){ for(int i=0;i (a,10); mySort (b,10); print_arr(a,10); print_arr(b,10); return 0; } 输出
9,4,6,2,0,2,5,3,3,2, C,F,E,G,I,J,E,G,C,H, ------------------- 0,2,2,2,3,3,4,5,6,9, C,C,E,E,F,G,G,H,I,J,
比如一个字符和int相加普通函数和函数模板的调用规则
- 调用普通函数,会转换
- 调用自动模板,会报错
- 显示指定类型,会转换
#includeusing namespace std; void myPrint(int a){ cout<<"调用的是普通函数n"; } template void myPrint(T a){ cout<<"调用的是函数模板n"; } template void myPrint(T a,T b){ cout<<"调用的是重载的函数模板n"; } int main(){ int a=0;int b=1; char c='a'; myPrint(a);//优先调用普通函数 myPrint<>(a);//用空模板参数列表来强调调用函数模板 myPrint(a,b);//调用重载的函数模板 myPrint(c);//当函数模板能更好的匹配,优先调用函数模板 return 0; } 结果:
调用的是普通函数 调用的是函数模板 调用的是重载的函数模板 调用的是函数模板模板的局限性 使用具体化的模板#include类模板using namespace std; class Person{ public: Person(string name,int age){ this->my_name=name; this->my_age=age; } string my_name; int my_age; }; template bool myCompare(T &a,T &b){ if(a==b){ return 1; } else{ return 0; } } //具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型 //具体化优先于常规模板 template<> bool myCompare(Person &a,Person &b){ if(a.my_age==b.my_age&&a.my_name==b.my_name){ return true; } else{ return false; } } void test01(){ int a=1,b=2; bool k=myCompare(a,b); if(k){ cout<<"相等n"; } else{ cout<<"不相等n"; } } void test02(){ Person a("Tom",10); Person b("Tom",10); bool k=myCompare(a,b); if(k){ cout<<"相等n"; } else{ cout<<"不相等n"; } } int main(){ test01(); test02(); return 0; } #includeusing namespace std; template class Person{ public: //别忘了构造函数的类型 Person(NameType name,AgeType age){ this->mName=name; this->mAge=age; } NameType mName; AgeType mAge; void showPerson(){ cout<<"name:"< mName<<",age:"< mAge< p("tom",9); p.showPerson(); } int main(){ test(); return 0; } 总结:类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板
类模板和函数模板的区别#includeusing namespace std; template class Person{ public: Person(NameType name,AgeType age){ this->mName=name; this->mAge=age; } NameType mName; AgeType mAge; void showPerson(){ cout<<"name:"< mName<<",age:"< mAge< p("tom",9); p.showPerson(); } void test01(){ Person p("asd",8); p.showPerson(); } void test02(){ Person p("asd",'A'); p.showPerson(); } int main(){ test(); test01(); test02(); return 0; } 其中带默认参数:
template类模板中成员函数创造时机 #include类模板对象做函数参数using namespace std; class Person1{ public: void showPerson1(){ cout<<"This is person1n"; } }; class Person2{ public: void showPerson2(){ cout<<"This is person2n"; } }; template class myClass{ public: T obj; void fun1(){ obj.showPerson1();} void fun2(){ obj.showPerson2();} }; void test01(){ myClass p; p.fun1(); //p.fun2() 编译出错 } void test02(){ myClass p; p.fun2(); } int main(){ test01(); test02(); return 0; }
补充:#includetypeid(T).name() #include类模板和继承#include #include using namespace std; template class Person{ public: Person(T1 name,T2 age){ this->mName=name; this->mAge=age; } void ShowPerson(){ cout<<"name:"< &p){ p.ShowPerson(); } void test01(){ Person p("qzs",100); printPerson1(p); } //参数类型模板化 template void printPerson2(Person &p){ p.ShowPerson(); cout<<"T1的类型为: "< p("zjh",18); printPerson2(p); } //整个类模板化,类模板配合函数模板 template void printPerson3(T &p){ p.ShowPerson(); cout<<"T1的类型为: "< p("kkk",50); printPerson3(p); } int main(){ test01(); test02(); test03(); return 0; } #include#include #include using namespace std; template class base{ T m; }; //class son:public base 报错:缺少 类模板 "base" 的参数列表 class Son:public base { }; void test01(){ Son s1; } template class Son2:public base { public: Son2(){ cout<<"T1的数据类型为: "< s2; }; int main(){ test01(); test02(); return 0; } 对于T,T1,T2的继承关系
类模板成员函数类外实现
#include#include #include using namespace std; template class Person{ public: Person(T1 name,T2 age); void ShowPerson(); T1 mName; T2 mAge; }; template Person ::Person(T1 name,T2 age){ this->mName=name; this->mAge=age; } template //返回类型+类名限定域+模板参数+函数名+参数 void Person ::ShowPerson(){ cout<<"name: "< mName<<" age:"< mAge< p("qzs",118); p.ShowPerson(); } int main(){ test01(); return 0; } 类模板成员函数,类外实现
类模板分文件编写
要加:Person
返回类型+类名限定域+模板参数+函数名+参数
基本都使用方法二:用hpp文件,#include"person.hpp",记住是".hpp"
person.hpp:#pragma once #includeusing namespace std; template class Person{ public: Person(T1 name,T2 age); void ShowPerson(); T1 mName; T2 mAge; }; template Person ::Person(T1 name,T2 age){ this->mName=name; this->mAge=age; } template void Person ::ShowPerson(){ cout<<"name :"< mName<<" age:"< mAge; } template.cpp:
#include#include #include #include"person.hpp"//头文件要用"" using namespace std; void test01(){ Person p("qzs",100); p.ShowPerson(); } int main(){ test01(); return 0; } 其中补充:#pragma once的意思是防止多次包含
类模板和友元
函数模板类内实现:#include#include #include //#include"person.hpp"//头文件要用"" using namespace std; template class Person{ //全局函数类内实现 friend void ShowPerson1(Person &p){ cout<<"类内name:"< &p); public://别忘了构造函数要放在public下,默认private Person(T1 name,T2 age){ this->Name=name; this->Age=age; } private: T1 Name; T2 Age; }; //全局函数类外实现 template void ShowPerson2(Person &p){ cout<<"类外name:"< p("qzs",100); ShowPerson1(p); ShowPerson2(p); } int main(){ test01(); return 0; } 其中类外会报错:if this is not what you intended, make sure the function template has already been declared and add <> after the function name here
如果这不是你想要的,确保函数模板已经被声明并添加<>在函数名后
对于全局函数类外声明:#include#include #include using namespace std; //再提前声明Person template class Person; //提前声明 template void ShowPerson2(Person &p){ cout<<"类外name:"< class Person{ friend void ShowPerson2<>(Person &p); public://别忘了构造函数要放在public下,默认private Person(T1 name,T2 age){ this->Name=name; this->Age=age; } private: T1 Name; T2 Age; }; void test01(){ Person p("qzs",100); ShowPerson2(p); } int main(){ test01(); return 0; } 需要做到:
1.类内friend void ShowPerson2<>(Person&p)加<>
2.在类上定义函数
3.在函数上声明类类模板案例所以建议类内实现
遇到的一类错误,void的返回return不加0
对于MyArray.hpp#pragma once #includeusing namespace std; template class MyArray{ public: //有参构造 MyArray(int capacity){ //cout<<"MyArray的有参构造调用n"; this->capacity=capacity; this->size=0; this->p=new T [this->capacity]; } //拷贝函数 MyArray(class MyArray &arr){ //cout<<"MyArray的拷贝构造调用n"; this->capacity=arr.capacity; this->size=arr.size; //this->p=arr.p; 浅拷贝,使不得 this->p=new T[arr.capacity]; for(int i=0;i capacity;i++){ this->p[i]=arr.p[i]; } } //析构函数 ~MyArray(){ //cout<<"MyArray的析构函数调用n"; if(this->p!=NULL){ delete []this->p; this->p=NULL; } } // operator 重载 防止浅拷贝 MyArray& operator=(const MyArray& arr){ //cout<<"MyArray的operator=调用n"; //先判断堆区内存是否释放 if(this->p!=NULL){ delete []this->p; this->p=NULL; this->capacity=0; this->size=0; } //深拷贝 this->p=new T[arr.capacity];//开的是和arr一样的大小 this->capacity=arr.capacity; this->size=arr.size; for(int i=0;i capacity;i++){ this->p[i]=arr.p[i]; } return *this; } //尾插法 void InsertTail(const T &val){ //判断容量是否等于大小 if(this->size==this->capacity){ cout<<"满了n"; return; } this->p[this->size]=val; this->size++;//size更新 } //尾删法 void DeleteTail(){ if(this->size==0){ cout<<"没元素可删了n"; return; } this->size--;//物理删除不清0 } //重载[],不然访问不到 T& operator[](int index){ //返回一个引用类型 可以保证外部修改 arr[5]=100 return this->p[index]; } //返回数组容量 int GetCapacity(){ return this->capacity; } //返回数组大小 int GetSize(){ return this->size; } private: T *p; int capacity; int size; }; 对于main.cpp
提供了三个测试案例#include#include #include #include"MyArray.hpp" #include #include using namespace std; #define random(a,b) (rand()%((b)-(a)))+(a) void test01(){ //模板别忘了加 MyArray arr1(5); MyArray arr2(arr1); MyArray arr3(100); arr1=arr3; arr1[5]; } void PrintArr(MyArray &arr,int len){ for(int i=0;i arr1(10); for(int i=0;i<5;i++){ arr1.InsertTail(random(0,10)); } PrintArr(arr1,5); cout< arr2(arr1); cout<<"arr2的打印输出"< name=name; this->age=age; } string name; int age; }; void PrintPersonArray(MyArray &p){ for(int i=0;i arr(10); arr.InsertTail(p1); arr.InsertTail(p2); arr.InsertTail(p3); arr.InsertTail(p4); arr.InsertTail(p5); PrintPersonArray(arr); cout<<"capacity:"<



