定义类模板
首先声明类模板,方法和声明函数模板一致。
template<typename T>
class Vector
{
T* _elems;
int _size, _capacity;
const int DEFAULT_CAPACITY = 3;
public:
Vector(int c=DEFAULT_CAPACITY, ...)
...
};
类模板与普通类功能大多数一致,除了多出一个类型参数T。在类模板外部定义成员函数时,需要使用类模板完整的类型限定符,下面定义构造函数:
template<typename T>
Vector<T>::Vector(int c, ...)
{
...
};
定义上面的类模板后,该类的类型为Vector<T>。类模板的成员函数相当于模板函数。
使用类模板继承:
template<typename T>
class Base
{
};
template<typename T>
class Derived: public Base<T>
{
};
继承时也应该使用完整的类型限定符Base<T>。
实例化类模板
定义一个类模板的实例对象:
Vector<int> intVector;
在类模板内部,会以int来实例化类型参数T。当我们调用它的成员函数时,成员函数也会被实例化(成员函数只会在被调用时才会被实例化)。
比如上面定义一个对象时,调用了默认构造函数,构造函数就会被实例化出一个int类型的版本。
而不被对象调用的成员函数,就不会对应的将其实例化,这样可以节省空间和时间成本。
但对于静态成员,在实例化一个类模板对象时,这些静态成员都会被实例化。
可以借助类型定义关键字typedef,更方便的使用类模板:
typedef Vector<int> IntVector;
IntVector intVector; //与上面的定义相同
由这两种方式定义的对象可以互相赋值。
类模板的特化
类模板的特化与模板函数的重载相似,都是为了优化基于某种特定类型的实现。下面的方式特化一个类模板:
template<>
class Vector<double>
{
...
};
特化的类模板内部不能出现被特化的类型参数T,必须使用特化的类型进行替代。与模板函数重载类似,特化类的实现可以与原类模板不同。
局部特化
局部特化多用于有多个类型参数的情况,指的是多个类型参数间的局部。
如下面的类模板:
template <typename T1, typename T2>
class MyClass
{
...
};
可以对其进行以下的局部特化:
- 两个模板参数具有相同类型:
template <typename T>
class MyClass<T,T>
{
};
- 只特化其中一个模板参数:
template<typename T>
class MyClass<T,int>
{
};
- 两个模板参数都特化为指针:
template<typename T1,typename T2>
class MyClass<T1*,T2*>
{
};
下面的实例对象:
Myclass<int,float> mif; //使用 MyClass<T1,T2>
MyClass<float,float> mff; //使用 MyClass<T,T>
MyClass<float,int> mfi; //使用 MyClass<T,int>
MyClass<int*,float*> mp; //使用 MyClass<T1*,T2*>
但上面的几种特化也会导致二义性的问题,比如当实例对象传入两个相同的指针时,他们对第一种和第三种特化同等程度的匹配。
这就需要特化一个传入两个相同指针的新特化类来解决:
template<typename T>
class MyClass<T*, T*>
{
};