函数重载是指在相同的函数名下,能够实现不同操作。系统根据参数的类型或参数个数的不同区分这些重载的函数。这样虽然很方便,但是出现了大量的代码冗余。该如何解决这个问题呢?
C++提供了模板。模板时类型参数化的工具。所谓类型参数化就是指把类型定义为参数,当参数实例化时,可以指定不同的数据类型,从而真正实现代码的可重用性。
模板分为函数模板和类模板,他们分别允许用户构造模板函数和模板类。如图:
当对每种数据类型执行相同的操作时,用函数模板来完成最为简便。只需要定义一次函数模板,根据调用函数时提供的参数类型,编译器会产生相应的目标代码函数,以正确处理每种类型的调用。
声明函数模板的格式为:
template
返回类型 函数名(模板形参表)
{
函数体
}
例如,输出不同类型数组的元素值可定义为函数模板:
template <class T>
void PrintArrary(T* Array, int count)
{
for (int i = 0; i < count; i++)
{
cout << Array[i] << " ";
}
cout << endl;
}
//也可以定义为
template <typename T>
void PrintArrary(T* Array, int count)
{
for (int i = 0; i < count; i++)
{
cout << Array[i] << " ";
}
cout << endl;
}
说明:1. T
是类型参数,它既可以是系统预定义的数据类型,也可以是用户自定义的类型;
2. 类型参数前需要加关键字class
(或typename
),这个class
并不是类的意思,而是表示任何类型;
3. 在使用模板函数时,关键字class
(或typename
)后面的类型参数,必须实例化,即采用实际的数据类型;
4. “<>
”里面的类型参数可以有一个或者多个类型参数,但多个类型参数之间要用逗号分隔。
例如:函数模板应用:输出不同类型数组的元素值。
#include
using namespace std;
template <class T>
void PrintArrary(T* Array, int count)
{
for (int i = 0; i < count; i++)
{
cout << Array[i] << " ";
}
cout << endl;
}
int main()
{
int a[5] = { 1,2,3,4,5 };
double b[7] = { 1.1,2.2,3.3,4.4,5.5,6.6,7.7 };
char c[6] = "hello";
PrintArrary(a, 5);
PrintArrary(b, 7);
PrintArrary(c, 6);
return 0;
}
说明:从本程序可以看出,使用函数模板不用单独定义三个函数,从而解决了当采用函数重载技术时所产生的代码冗余问题。
注意:1. 在执行PrintArray
函数调用时,根据参数的类型,系统自动在内存中生成一个模板函数(实例化函数),并执行该函数;
5. 函数模板中可以使用多个类型参数,但每个模板形参前必须有关键字class
或typename
。
6. 在template
语句和函数模板定义语句之间不允许有其他语句。
7. 模板函数类似于函数重载,但与函数重载不同。在进行函数重载时,每个函数体内的动作既可以相同也可以不同,但模板函数中的动作必须相同。如下面的函数只能用函数重载,而不能用模板函数。
void Print(char* name)
{
cout << name << endl;
}
void Print(char* name, int no)
{
cout << name << no << endl;
}
T
可以实例化为各种类型,但实例化T
的各模板实参之间必须保证类型一致,否则将发生错误。类是对一组对象的公共性质的抽象,而类模板是更高层次的抽象。类模板(类属类或类生成类)允许用户为类定义一种模式,使类中的某些数据成员、成员函数的参数或返回值可以根据需要取任意类型。
类模板的定义格式为:
template
class 类名
{
//```
};
说明:1. 在每个类模板定义之前,都需要在前面加上模板声明。在使用类模板时,应将它实例化为一个具体的类(模板类),类模板实例化为模板类的格式为:类名<具体类型名>
;
2. 模板类可以有多个模板参数;
3. 在类定义体外定义成员函数时,若该成员函数中有类型参数,则需要在函数体外进行模板声明,即在类名和函数名之间加上
,格式为:返回类型 类名
;
4. 类模板不代表一个具体的、实际的类,而是代表一类类。因此在使用时,必须将类模板实例化为一个具体的类,格式为:类名 <实际的类型> 对象名
;
例如:用类模板实现栈的基本运算。
#include
using namespace std;
const int SIZE = 100;
template <class T>
class Stack
{
public:
Stack();
void Push(T x);
T Pop();
private:
T s[SIZE];
int top;
};
template<class T>
Stack<T>::Stack()
{
top = -1;
}
template<class T>
void Stack<T>::Push(T x)
{
if (top == SIZE - 1)
{
cout << "Stack is full" << endl;
return;
}
s[++top] = x;
}
template<class T>
T Stack<T>::Pop()
{
if (top == -1)
{
cout << "Stack underflow" << endl;
return 0;
}
return s[top--];
}
int main()
{
Stack<int> a;
for (int i = 0; i < 10; i++)
{
a.Push(i);
}
for (int i = 0; i < 10; i++)
{
cout << a.Pop() << " ";
}
return 0;
}