模板可分为函数模板和类模板。
函数包括声明和定义,声明在.h文件中,定义在.cpp文件中。函数模板也包括声明和定义,只不过它们都位于.h文件中。使用顺序是在.h文件中声明 -> 在.h文件中定义 -> 在.cpp文件中实例化并使用。
类包括定义和实现,定义在.h文件中,实现在.cpp文件中。类模板也包括定义和实现,只不过它们都位于.h文件中。使用顺序是在.h文件中定义 -> 在.h文件中实现 -> 在.cpp文件中实例化并使用。
注明:编译器将某一.cpp文件编译成.o文件的过程中,会忽略该.cpp文件中的模板,直到在该.cpp文件中发现了模板实例化,编译器才会对该模板进行编译。
也就是说:不进行实例化,模板写了也白写,因为编译器会直接忽略它。
函数模板的声明和定义位于.h文件中,其格式如下所示:
//sample.h
//函数模板的声明
template void swap(T& t1, T& t2);
//函数模板的定义
template void swap(T& t1, T& t2)
{
T temp;
temp = t1;
t1 = t2;
t2 = temp;
}
函数模板的实例化位于.cpp中,因为在.cpp中我们要使用模板了。
实例化分为隐式实例化、显示模板实参、显示实例化三种。为了方便记忆,我把这三种实例化方式与函数模板具体化一起记忆。
它们的格式复杂程度是按顺序依次递升的:隐式实例化->显示模板实参->显示实例化->具体化。其格式如下所示:
//main.cpp
#include
#include "sample.h"
int main(int argc, char* argv[])
{
int num1 = 1, num2 = 2;
//隐式实例化:就像调用普通函数一样
swap(num1, num2);
//显示模板实参
swap(num1, num2);
//显示实例化
template void swap(int& t1, int& t2);
swap(num1, num2);
cout<<"num1:"<
函数模板具体化应放在.h文件中,和函数模板的定义放在一块。
//sample.h
//函数模板具体化
template <> void swap(int& t1, int& t2)
{
//具体实现过程
...
...
}
咱家喜欢使用显示模板实参实例化函数模板。
类模板的定义和实现位于.h文件中,其格式如下所示:
//sample.h
#include
//类模板的定义
template
class Compare
{
public:
Compare(T i,T j);
T max();
void ShowCPNumber();
template
void Show(B b);
private:
T x,y;
};
//类模板的实现
//构造函数的类外定义
template
Compare::Compare(T i,T j)
{
x = i;
y = j;
}
//带类型参数的成员函数的类外定义
template
T Compare::max()
{
return (x>y)?x:y;
}
//不带类型参数的成员函数的类外定义
template
void Compare::ShowCPNumber()
{
cout<<"number1:"<< x <
template
void Compare::Show(B b)
{
cout<<"number3:"<< b <
从上面可以发现:类模板中的成员函数,可以在类模板外定义。此时,不论成员函数是否为构造函数,是否为模板函数,是否包含类型参数,C++都规定:
1)需要在成员函数定义之前进行模板声明;
2)在成员函数名前缀上"类名<类型参数>::";
类模板我一般使用显示模板实参实例化,其它实例化方法不是很清楚。不过,其实知道显示模板实参这一种实例化方法就够了。
类模板实例化格式如下所示:
//main.cpp
#include "sample.h"
int main(int argc, char* argv[])
{
//显示模板实参
Comparecom1(3,7); //用类模板定义对象com1,此时T被int替代
Comparecom2(12.34,56.78); //用类模板定义对象com2,此时T被double替代
Comparecom3('a','x'); //用类模板定义对象com3,此时T被char替代
cout<<"其中的最大值是:"<