类模板语法
和函数模板的写法一样,在template的下一行紧跟一个类,就是类模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include<iostream> #include<string.h> using namespace std; template<class typeAge,class typeName> class Person{ public: Person(typeAge age,typeName name){ this->_age = age; this->_name = name; } typeAge _age; typeName _name; }; int main(){ Person<int, string> p(20,"Tom"); }
|
类模板特点
类模板没有自动类型推导的使用方式。
类模板在模板参数列表中可以有默认参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include<iostream> #include<string.h> using namespace std; template<class typeAge,class typeName> class Person{ public: Person(typeAge age,typeName name = string){ this->_age = age; this->_name = name; } typeAge _age; typeName _name; }; int main(){ Person<int> p(20,"Tom"); }
|
例子中,name的默认参数是string。(默认参数的设置和函数默认参数的规则类似,默认参数必须要在非默认参数后面出现)
类模板中成员函数的创建时机
类模板中的成员函数在调用时才创建,一开始无法确定成员变量的数据类型,只有当调用了类模板后才能确定成员变量的数据类型,类模板中的成员函数在这个时机,才创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include<iostream> #include<string.h> using namespace std; class Person{ public: void showPerson(){ printf("show"); } }; template<class T> class test{ public: T obj; void fun(){ obj.showPerson(); } }; int main(){ test<Person> m; m.fun(); return 0; }
|
例子中类模板class中的fun( )只有当接收了T的数据类型才能创建,若数据类型T不是Person,无法调用fun( )函数,还会报错。创建的时机是被调用后。
类模板对象做函数参数
一共有三种传入方式:
1、指定传入的类型: 直接显示对象的数据类型
事先定义好函数要传入的类型,如这里的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include<iostream> #include<string.h> using namespace std;
template<class T1,class T2> class test{ public: test(T1 age, T2 name){ this->age = age; this->name = name; } void show(){ printf("show"); } T1 age; T2 name; };
void showfunc(test<int, string> &p){ p.show(); } int main(){ test<int, string> person(20,"Tom"); showfunc(person); return 0; }
|
2、参数模板化:将对象中的参数变为模板进行传递
1 2 3 4 5
| template<class T1, class T2> void showfunc(test<T1, T2> &p){ p.show(); }
|
3、整个类模板化:将这个对象类型 模板化进行传递
1 2 3 4 5
| template<class T> void showfunc(T &p){ p.show(); }
|
第一种比较实用
类模板与继承
当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
如果不指定,编译器无法给子类分配内存
1 2 3 4 5 6 7 8
| template<class T> class Base{ T m; };
class Son: public Base<int>{ };
|
如果想灵活指定出父类中T的类型,子类也需变为类模板‘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include<iostream> #include<string.h> using namespace std; template<class T> class Base{ public: T m; };
template<class T1, class T2> class Son: public Base<T2>{ public: T1 one; }; int main(){ Son<char, int> m; }
|
类模板成员函数类外实现
假设有一个类Person
构造函数类外实现
1 2 3 4 5 6 7 8 9 10 11
| class Person{ public: T1 name; T2 age; };
template<class T1,class T2> Person<T1,T2>::Person(T1 name,T2 age){ this->name = name; this->age = age; }
|
成员函数的类外实现(假设Person类存在)
1 2 3 4 5
| template<class T1,class T2> void Person<T1,T2>::showPerson(){ }
|
类模板分文件编写
讲.h和.cpp 中的内容写到一起,再将后缀名改为.hpp(约定俗成的)
将类模板和调用编写到一起,否则会导致链接不到类模板中的成员函数(因为该函数是在被调用时才生成)
解决方法:将声明和实现写到同一个.hpp文件中。
类模板和友元
全局函数 类内实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include<iostream> #include<string.h> using namespace std; template<class T1, class T2> class Person{ friend void printPerson(Person<T1,T2> &p){ cout<<p.name<<endl; cout<<p.age; }
public: Person(T1 name, T2 age){ this->age = age; this->name = name; } private: T1 name; T2 age; };
int main(){ Person<string,int> p("Tom",20); printPerson(p);
return 0; }
|
全局函数 类外实现(比较复杂)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| template<class T1, class T2> class Person;
template<class T1, class T2 void printPerson(Person<T1,T2> &p){ cout<<p.name<<endl; cout<<p.age; } template<class T1, class T2> class Person{ friend void printPerson<>(Person<T1,T2> &p) public: Person(T1 name, T2 age){ this->age = age; this->name = name; } private: T1 name; T2 age; };
|
总结:建议写类内实现