C++中将泛型思想引入到了类,实现了类模板,使得类的实现不再关注数据元素的具体类型,而只关注类所需实现的功能,适用于编写数据结构相关代码。
C++中的类模板以相同的方式处理不同的类型,在类的声明前使用template关键字标识将要泛型编程,<typename T>用于说明类中使用的T是泛指类型,类模板只能显式指定具体类型,无法像函数模板那样能够自动推导,下面给出定义过程和使用方法:
template < typename T >
class Operator
{
public:
T add(T a, T b)
{
return a + b;
}
};
使用:
Operator<int> op1;//使用具体类型<type>定义对象
cout << op1.add(1, 2) << endl;
注意:
类模板声明的泛指类型T可以出现在类模板的任意地方。
编译器对类模板的处理方式和函数模板相同,通过具体类型从类模板产生不同的类,在声明的地方对类模板代码本身进行编译,在使用的地方对参数替换后的代码进行编译。
类模板的工程应用:
类模板必须在头文件中定义。
类模板不能分开实现在不同的文件中。
类模板外部定义的成员函数需要加上模板< >声明。
以上并非硬性规定,只是工程中使用起来阅读性更强。
#ifndef _OPERATOR_H_
#define _OPERATOR_H_
template < typename T >
class Operator
{
public:
T add(T a, T b);
T multiply(T a, T b);
};
template < typename T >
T Operator<T>::add(T a, T b)
{
return a + b;
}
template < typename T >
T Operator<T>::multiply(T a, T b)
{
return a * b;
}
#endif
这就完全符合工程应用中的规定。实现是在头文件中,但是使用依旧和普通类成员函数一样,在源文件中使用。
多参数类模板
类模板可以定义任意多个不同的类型参数。
template
< typename T1, typename T2 >
class Test
{
public:
void add(T1 a, T2 b);
};
在使用的时候需要将参数类型显式指定出来,例如:
Test<int, float> t1;
类模板可以被特化,就是指定类型参数的类模板的特定实现,和前面一样,部分类型参数必须显式指定,特化模型有两种,部分特化和完全特化,部分特化就是多个参数都一样,但是并未指定出具体类型,完全特化就是多个参数显式指定出具体类型,用前面的类模板做例子实现部分特化和完全特化:
部分特化:
template< typename T >
class Test < T, T > // 当 Test 类模板的两个类型参数完全相同时,使用这个实现
{
public:
void add(T a, T b);
};
完全特化;
template< >
class Test < int, int > // 当 Test 类模板的两个类型参数显式指定,使用这个实现
{
public:
void add(int a, int b);
};
指针相关的特化实现;
template< typename T1, typename T2 >
class Test < T1*, T2* > // 指针的特化实现
{
public:
void add(T1* a, T2* b);
};
这些
特化只是模板的分开实现,本质上还是同一个模板,并且所有特化模板的使用方式都是统一的,必须显式指定每一个类型参数,当你使用了不同组合的参数类型,是编译器自动选择调用哪一个特化实现的。
类模板特化与重定义的区别:
重定义:一个类模板和一个新类(或者两个类模板),使用的时候需要考虑如何选择的问题。
特化:以统一的方式使用类模板和特化类,编译器自动优先选择特化类。
函数模板也支持特化,但是只支持参数类型完全特化。
函数模板和完全特化的函数模板:
template< typename T >//函数模板
bool Equal(T a, T b)
{
//...
//...
}
template< >//完全特化
bool Equal<double>(double a, double b)
{
//...
//...
}
工程中 建议当需要重载函数模板时优先考虑使用模板特化,当模板特化无法满足要求再使用函数重载。