一、概述
本文讲解了C++函数模板和类模板的相关知识,当需要多个函数对多个不同的数据类型的数据进行相同的处理时,需要多次重载函数,而使用函数模板,编译器产生不同的目标代码函数来适当地处理每个函数的调用,显得更加简便。将这一概念引入至类中,将类中数据成员的类型都参数化(把数据类型定义为参数),在初始化类对象的时候,根据实参确定数据类型。
二、函数模板
当需要函数用于执行相似的操作,这些操作处理不同数据类型上的相同程序逻辑,即函数要处理的数据类型不同,但程序逻辑一样,那么使用函数模板可以简便地对函数进行重载,而不用进行多次重载。
例如求最大值的函数maximum(),如果要对int、float或double型的3个变量求出最大值,那么将要重载函数2次以上,而使用函数模板可以使程序更简洁。#include <iostream>
using namespace std;
template<class T> //表示下面为一函数模板
T maximum( T value1 ,T value2 ,T value3)
{
T maximumValue = value1;
if (value2 >maximumValue)
maximumValue = value2;
if(value3 >maximumValue)
maximumValue = value3;
return maximumValue;
}
int main()
{
int i1,i2,i3;
cout<<"Input three integer values: ";
cin>>i1>>i2>>i3;
cout<<"The maximum integer value is: "
<<maximum(i1 ,i2,i3)<<endl;
double d1,d2,d3;
cout<<"Input three double values: ";
cin>>d1>>d2>>d3;
cout<<"The maximum double value is: "
<<maximum(d1 ,d2,d3)<<endl;
char c1,c2,c3;
cout<<"Input three characters values: ";
cin>>c1>>c2>>c3;
cout<<"The maximum characters value is: "
<<maximum(c1 ,c2,c3)<<endl;
return 0;
}
函数模板的声明为
template < typename T> //尖括号可以有多个形参
或者是
template < class T>
或者是
template<>表示下面为一模板函数,尖括号中class或typename(两者区别不大),说明后面的一个字符T(也可以用其他符号)是表示一个类型(可为int、float、结构体等),接下来函数定义中则使用T作为一种泛型类型,可作为返回值类型,或函数形参的类型。
如上文的T maximum( T value1 ,T value2 ,T value3)
三、类模板
类模板的声明及定义如下:
template <typename或class T>
class 类名
{
//具体定义…..
}
其中template<>中的形参可以多个
例子如下:
//TemplateClass.h
#ifndef TemplateClass_H
#define TemplateClass_H
#include <iostream>
using std::cout;
using std::endl;
template< typename T1 ,typename T2 >
class ClassA
{
public:
ClassA(T1 ,T2);
void print();
private:
T1 a;
T2 b;
};
#endif
template< typename T1 ,typename T2 > //注意再每个函数头前均有此声明语句
ClassA<T1,T2>::ClassA(T1 v1 ,T2 v2 ) //构造函数
:a(v1),b(v2)
{
}
template< typename T1 ,typename T2 >
void ClassA<T1,T2>::print() //print函数
{
cout<<a<<" "<<b<<endl;
}
//main.cpp
#include "TemplateClass.h"
int main()
{
ClassA<char,int> a('a',1);
a.print();
return 0;
}
可看出该类的成员函数均为模板函数,在main函数中初始化类对象时,编译器将根据实参类型确定T1,T2的类型。
四、模板特化
如果我们想给模板函数(或类模板)实现一个已确定数据类型的函数,那么可以才用模板特化,当遇到该类数据类型的数据时,则调用该模板特化。特化分为全特化和偏特化,函数模板只有全特化,类模板有全特化和偏特化。
(1)函数模板特化
在前面提到的求最大值的函数maximum(),现在针对int类型写一模板特化如下:
template<> //表明下面是一个模板函数,由于针对int型,尖括号内省去
int maximum( int value1 ,int value2 ,int value3)
{
int maximumValue = value1;
if (value2 >maximumValue)
maximumValue = value2;
if(value3 >maximumValue)
maximumValue = value3;
cout<<value1<<"+"<<value2<<"+"<<value3 //
<<"="<<value1+value2+value3<<endl; //增加求三者之和
return maximumValue;
}
则当传入maximum()的实参均为int型时,程序优先调用该程序,结果
(2)类模板特化
类模板有2种形式,全特化和偏特化,先介绍全特化,在上面类模板的讲解中,将TemplateClass.h头文件中的ClassA类分别全特化、偏特化,代码如下:
//TemplateClass.h
#ifndef TemplateClass_H
#define TemplateClass_H
#include <iostream>
using std::cout;
using std::endl;
typedef struct point
{
double x;
double y;
};
template< typename T1 ,typename T2 >
class ClassA
{
public:
ClassA(T1 v1,T2 v2):a(v1),b(v2){};
void print()
{
cout<<a<<" "<<b<<"\n\n";;
}
private:
T1 a;
T2 b;
};
#endif
template<> //将ClassA类全特化,即将T1,T2确定为结构体point类型
class ClassA<point ,point>
{
public:
ClassA(point p1,point p2):a(p1),b(p2){};
void print()
{
cout<<a.x<<" "<<a.y<<endl;
cout<<b.x<<" "<<b.y<<"\n\n";;
}
private:
point a;
point b;
};
template<typename T2 > //将ClassA类偏特化,只将T1确定为结构体point类型,T2不特化
class ClassA<point ,T2>
{
public:
ClassA(point p1,T2 v2):a(p1),b(v2){};
void print()
{
cout<<a.x<<" "<<a.y<<endl;
cout<<b<<"\n\n";
}
private:
point a;
T2 b;
};
//main.cpp
#include "TemplateClass.h"
int main()
{
ClassA<char,int> a('a',1); //调用类模板
a.print();
point p1;
point p2;
p1.x = 0.1;
p1.y = 0.2;
p2.x = 1.1;
p2.y = 1.2;
ClassA <point,point> b(p1,p2); //调用类模板全特化
b.print();
ClassA<point ,int> c(p1 ,1); //调用类模板偏特化
c.print();
return 0;
}
结果
五、非类型模版参数
非类型模板参数指定是在函数模板(或类模板)中,模板template<>,尖括号中的参数除了typename T(类型),还可增加常整数(包括枚举)或者指向外部链接对象的指针,浮点型float和类对象是不允许作为非类型模板参数的。示例如下:
template<typename T ,int MAXSIZE>
class ClassB
{
public:
ClassB()
{
for(int i=0;i<MAXSIZE ;i++)
elem[i] =i+1;
}
void print()
{
for(int i=0;i<MAXSIZE ;i++)
cout<<elem[i]<<" ";
cout<<endl;
}
private:
T elem[MAXSIZE];
};
int main()
{
ClassB<int ,10> a;
a.print();
return 0;
}
此时MAXSIZE相当于全局变量的作用,但其为一个常整数。