模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性。模版可以分为两类,一个是函数模版,另外一个是类模版。
函数模板
函数模板的一般写法:
template <class T>
返回类型 函数名(形参表){
//函数主体
}
或者
template <typename T>
返回类型 函数名(形参表){
//函数主体
}
template是一个声明模板的关键字,表明一个模板关键字的class或typename不能省略,来看一个具体例子
#include <iostream>
#define SQUARE(X) X*X
using namespace std;
inline double square(double x);
template <class T>
T MinNum(T x, T y){
return (x<y?x:y);
}
int main() {
double a,b,c;
int x,y;
x = 3;
y = 10;
a = square(5.0);
b = square(2.2+1.1);
c = SQUARE(2.2+1.1);
cout << a << endl;
cout << b << endl;
cout << c << endl;
cout << MinNum(a, b) << endl;
cout << MinNum(x, y) << endl;
return 0;
}
inline double square(double x){
return x*x;
}
程序分析:程序中定义了双精度浮点类型变量a,b。 定义了整型变量x,y。在比较大小时同都使用MinNum(T x, T y)函数。实例化MinNum(a,b)是T为double型,实例化MinNum(x,y)时 T为int 型
类模板
类模板的一般形式如下:
Template <class T>
class 类名{
//类定义
}
其中,template是声明各模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个。
例如:定义一个类模板:
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
template <class T>
class Stack {
private:
vector<T> elems; // 元素
public:
void push(T const&); // 入栈
void pop(); // 出栈
T top() const; // 返回栈顶元素
bool empty() const{ // 如果为空则返回真。
return elems.empty();
}
};
template <class T>
void Stack<T>::push (T const& elem)
{
// 追加传入元素的副本
elems.push_back(elem);
}
template <class T>
void Stack<T>::pop ()
{
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
// 删除最后一个元素
elems.pop_back();
}
template <class T>
T Stack<T>::top () const
{
if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
// 返回最后一个元素的副本
return elems.back();
}
int main()
{
try {
Stack<int> intStack; // int 类型的栈
Stack<string> stringStack; // string 类型的栈
// 操作 int 类型的栈
intStack.push(7);
cout << intStack.top() <<endl;
// 操作 string 类型的栈
stringStack.push("hello");
cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
}
catch (exception const& ex) {
cerr << "Exception: " << ex.what() <<endl;
return -1;
}
}
当上门的代码被编译和执行时,产生如下结果
7
hello
Exception: Stack<>::pop(): empty stack
模板与重载的区别
-
从代码中我们可以学习到,模板的定义方式一般有两种,分别为:template < typename T> 或 template 。有人可能会问一个typename和一个class这里面有什么区别,其实早期的C++并没有typename这个关键字,所以不论是函数模板还是类模板,都使用class的这种定义方式,后面C++完善,于是多出了typename,用来区分定义的是函数模板还是类模板,但本质都是一样的。
-
所谓的函数模板,实际上是建立一个通用的函数,其函数的类型和形参的类型不具体指定,用一个虚拟的类型来代表,这个通用的函数就成为函数模板。凡是函数体相同的函数都可以用这个模板来代替,而不必定义多个函数,只需在模板中定义一次就行了,在调用函数的时候系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。
-
相对于函数重载而言,模板具有得天独厚的优势,它不需要重复定义,所以使用起来比函数重载更简洁,但应注意的一点,函数模板只适用于函数的参数个数相同而类型不同,且函数体相同的情况,如果参数的个数不同,则不能用函数模板,这就是函数模板相对于函数重载的缺陷。
一个函数重载的例子如下:
#include <iostream>
using namespace std;
class printData
{
public:
void print(int i) {
cout << "整数为: " << i << endl;
}
void print(double f) {
cout << "浮点数为: " << f << endl;
}
void print(char c[]) {
cout << "字符串为: " << c << endl;
}
};
int main(void)
{
printData pd;
// 输出整数
pd.print(5);
// 输出浮点数
pd.print(500.263);
// 输出字符串
char c[] = "Hello C++";
pd.print(c);
return 0;
}