模板的作用
C++中,模板的作用就是实现代码的重用,通过将某种数据类型定义为参数,然后将不同的数据类型按照实参形式传送而实现代码重用
比如如下的程序
int min(int x, int y)
{return (x<y)? x:y;}
float min(float x, float y)
{return (x<y)? x:y;}
double min(double x, double y)
{return (x<y)?x:y;}
在以上的例子中,同样的功能和标识符的函数,因为数据类型不同需要进行重载,使用函数模板就可以避免这样浪费的情况发生
函数模板
函数模板将数据类型作为参数,将功能相同的函数使用一个通用的模板来完善,是不同的形参都可以调用该模板,避免函数的重复设计占用资源与时间
template<class T1, class T2,...>
返回值 函数名(形参表){
...
}
class后面所跟的是类型参数名,是后面函数的形参表中参数的名称
#include<iostream>
using std::cout;
using std::endl;
template<class T>
T min(T x, T y)
{
return (x < y) ? x: y;
}
void main()
{
int n1 = 2, n2 = 10;
double d1 = 1.5, d2 = 5.6;
cout << "smaller integer" << min(n1, n2)<<endl;
cout << "smaller double" << min(d1, d2);
}
这个函数模板就可以以一个函数实现之前多个函数的功能,极大节省了时间与空间。
这里的T就起到一个替代作用,在不确定输入的是什么数据类型的情况下代替精确的数据类型
类模板
类模板是类定义的一种模式,他将类中的数据成员各成员函数的参数值故意者返回值定义为模板,在使用中,改模板可以是任何数据类型。
类模板不是一个具体的类,是指具有相同特性但成员的数据类型不同的一族类
template<class T>//或者<typename T>
class 类名{
...
}
下面举一个例子说明模板类是如何使用的
#include<iostream>
using std::cout;
using std::endl;
class A
{
public:
A(int i) { m_A = i; }
~A() {}
static void print()
{
std::cout << "A" << endl;
}
friend class B;
protected:
int m_A;
};
class B {
public:
B(int i)
{
m_B = i;
}
static void print()
{
cout << "B" << endl;
}
void show(B b)
{
b.a->m_A = 3;
b.m_B = 2;
}
private:
A* a;
int m_B;
};
template<typename T1, typename T2>
class CTestTemplate
{
public:
CTestTemplate(T1 t)
{
m_number = t;
}
void print()
{
T2::print();
cout << m_number << endl;
}
private:
T1 m_number;
};
void main()
{
CTestTemplate<int, B>testtem(3);
testtem.print();
}
本例首先定义了A类,在该类中又定义了一个输出函数,将A中的成员变量输出,后又定义了一个与A类相似的B类,输出了B类的成员内容。定义了类模板类CTestTemplate,在该类中分别对其中的类成员T1和T2进行了操作,将T1赋给了成员变量,调用了T2的输出函数将结果输出
简单来说,类模板也是给输入类型不确定的类进行设计
模板参数
模板可以看做一种类型,在使用模板函数的时候也就应该会产生它的一个实例。
对平台类型实例化的时候通常需要提供必要的参数,模板函数并不例外,只是C++的模板参数不是一般情况下的参数,而是一种特定的类型。也就是说,在实例化一个函数模板的时候,需要以类型作为参数
对于模板参数的调用,一般有以下两种方式
1.显示实例化模板参数
#include<iostream>
using std::cout;
using std::endl;
template<typename T>
inline T const&max(T const&a, T const&b)
{
return a < b ? a : b;
}
int main()
{
cout<<max<double>(4, 4.2);
}
2.隐式地实例化函数模板
#include<iostream>
using std::endl;
using std::cout;
template<typename T>
inline T const& max(T const& a, T const& b)
{
return a < b ? a : b;
}
int main()
{
int i = max(42, 66);
cout << i;
}
这两组代码看起来是相似,不同之处只是在调用时是否明确调用的是模板中的哪一种数据类型。
T只是一个数据类型的“代号”,如果不明确需要调用的数据类型的话,函数便无从下手。
模板的特殊化
模板的特殊化指的是当模板中的pattern有确定的类型时,模板有一个具体的实现。
#include<iostream>
using namespace std;
template<class T>
class Pair
{
T value1, value2;
public:
Pair(T first, T second)
{
value1 = first;
value2 = second;
}
T module()
{
return 0;
}
};
template<> class Pair<int>
{
int value1, value2;
public:
Pair(int first, int second)
{
value1 = first;
value2 = second;
}
int module();
};
int Pair<int>::module()
{
return (value1 % value2);
}
int main()
{
Pair<int>myints(100, 75);
Pair<float>myfloats(100.0, 75.0);
cout << myints.module()<<endl;
cout << myfloats.module();
return 0;
}
模运算只能对整型生效,所以这里需要在输入非整型实数时让函数值总是返回0,专门将模板定义为int型使用
重载和函数模板
C++支持函数模板的重载,其匹配规则如下
- 寻找和使用最符合函数名和函数类型的函数,若找到则调用
- 寻找一个函数模板,将其实例化产生一个匹配的目标函数,若找到则调用
- 寻找可以通过类型转换进行参数匹配的重载函数,若找到则调用
- 如果按以上步骤均未找到匹配函数,则调用错误
- 如果调用有多于一个的匹配选择,则调用匹配出现二义性
下面使用一个程序详解重载的函数模板
#include<iostream>
using namespace std;
template<class T>
const T& Max(const T& x, const T& y)
{
cout << "A template function! Max is:";
return (x > y) ? x : y;
}
template<class T>
const T& Max(const T& a, const T& b, const T& c)
{
T s;
s = Max(a, b);
return Max(s, c);
}
const int& Max(const int& x, const int& y)
{
cout << "An overload function with int,int Max is:";
return (x > y) ? x : y;
}
const char Max(const int& x, char const& y)
{
cout << "An overload function with int, char, Max is:";
return (x > y) ? x : y;
}
void main()
{
int i = 10;
char c = 'a';
double f = 98.74;
cout << Max(i, i) << endl;
cout << Max(c, c) << endl;
cout << Max(3.3, 5.6, 6.6) << endl;
cout << Max(i, c) << endl;
cout << Max(c, i) << endl;
cout << Max(f, f) << endl;
cout << Max(f, i) << endl;
}
本例中首先定义了一个函数模板用以取最大值,接下来对该函数模板进行重载,然后分别用不同函数重载函数模板