类模板
背景:
在调用类模板时,指定参数,由编译系统根据参数提供的数据类型自动产生相应的模板类
类模板的定义
template <class 类型参数1, class 类型参数2, ...>
class 类模板名
{
成员函数和成员变量;
};
- 定义成员函数
template <类型参数表>
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表)
{
...
}
- 用类模板定义对象的写法:
类模板名 <真实类型参数表> 对象名(构造函数实际参数表);
如果类模板有无参构造函数,那么也可以只写为:
类模板名 <真实类型参数表> 对象名;
实例:Pair类模板
template <class T1, class T2>
class Pair {
public:
T1 key;
T2 value;
Pair(T1 k,T2 v):key(k),value(v){};//构造函数
bool operator< (const Pair<T1,T2>&p) const;
//运算符重载,其传递的函数是一个Pair类型的一个指针的引用
//const说明只是取比较大小,而不改变原来的值
};
template<class T1, class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2>&p) const{ //Pair的成员函数,注意标记作用域
return key < p.key;
}
int main() {
Pair<string,int> student("Tom",19);
//实例化出一个类,注意传入真实参数型列表
//T1 被替换为string T2被替换为int
//定义Pair类的student对象
cout<<student.key<<" "<<student.value;
return 0;
}
使用类模板声明对象
- 编译器由类模板生成类的过程叫类模板的实例化,编译器自动用具体的数据类型替换类模板中的类型参数,生成模板类的代码
- 由类模板实例化得到的类叫模板类,
- 为类型参数指定的数据类型不同, 得到的模板类不同
- 同一个类模板的两个模板类是不兼容的,即便其源于同一个类模板,如下列所示:
Pair<string,int> *p;
Pair<string, double> a;
p = &a; //wrong
函数模板作为类模板成员
#include <iostream>
using namespace std;
template <class T>
class A
{
public:
template<class T2>
// 函数模板不能和类模板的的参数相同!
// 否则报错:declaration of class X shadows template parm class X
void Func(T2 t)
{
cout << t;
} //成员函数模板
};
int main()
{
A<int> a;
a.Func('K'); //成员函数模板 Func被实例化;T2 对应char
return 0;
}
类模板与非类型参数
类模板的 <类型参数表>
中可以出现非类型参数:
- 非类型参数:用来说明类模板中的属性
- 类型参数:用来说明类模板中的属性类型,成员操作的参数类型和返回值类型
template <class T, int size>
class CArray
{
T array[size];
//用非参数类型int size来标记array的大小,是一个固定的属性
public:
void Print()
{
for(int i = 0; i < size; ++i)
cout << array[i] << endl;
}
};
类模板与继承
通常而言,一共有四种方式:
- 类模板派生出类模板
- 模板类(即类模板中类型/非类型参数实例化后的类)派生出类模板
- 普通类派生出类模板
- 模板类派生出普通类
下面我们分别对上述几种方式结合例子加以说明:
- 类模板派生出类模板
template <class T1, class T2>
class A {
T1 v1;
T2 v2;
};
template <class T1, class T2>
class B : public A<T2, T1> {
T1 v3;
T2 v4;
};
template <class T>
class C : public B<T, T> {
T v5;
};
int main() {
B<int,double> obj1; //T1替换为int,T2替换为double
C<int> obj2;
return 0;
}
在对B类进行实例化过程中,我们相当于调用了下述语句:
class B<int,double>:public A<double,int>{
int v3; double v4;
};
class A<double, int> {
double v1; int v2;
};
- 从实例化后的模板类派生出类模板
template <class T1, class T2>
class A {
T1 v1;
T2 v2;
};
class B : public A<int, double> {//对类模板实例化,变成模板类
T v;
};
int main() {
B<char>obj1;
return 0;
}
此时,自动生成两个模板类:
A<int,double>
B<char>
- 普通类派生出类模板
class A {
int v1;
};
template <class T>
class B : public A {
T v;
};
- 模板类派生出普通类
template <class T>
class A {
T v1;
int n;
};
class B :public A<int> {//模板类实例化作为父类
double v;
};