1、什么是模板?
(1)可以这样来解释这个问题,例如当我们需要定义多个函数,而这个函数功能其实都是一样的,例如两个数相加的函数,
只是相加的两个数的类型不相同而已,这就导致我们需要定义多个函数;当我们使用了函数模板之后,我们只需要定义
一个函数模板,这个函数模板的功能就是实现两个数相加的操作,而且可以传入自己指定的数据类型,这样我们就不用定义
多个函数了,所以可以认为,模板就是一种可以产生一系列功能相同而数据类型不同的函数或者是类的 "机器"。
(2)模板的形式:函数模板、类模板
(3)模板的声明格式
函数模板:
template<typename 类型参数>
返回类型 函数名(模板形参表)
{
函数体
}
或
template<class 类型参数>
返回类型 函数名(模板形参表)
{
函数体
}
类模板:
template <typename 类型参数>
class 类名
{
类成员声明
}
或
template <class 类型参数>
class 类名
{
类成员声明
}
在上面的template后面的参数可以是多个,也可以是一个,而且修饰词typename和class可以混用,可以认为他们两个关键字没有什么区别,都可以使用;
template后面的"<>"尖括号可以紧跟在template关键字后面,也可以用空格来隔开;
(4)需要注意的是:typename或者是class指定的是一种数据类型,其实除了可以指定数据类型之外,还可以指定某种数据类型的变量,例如下面的
template <typename 形参名,class 形参名,int 形参名, double 形参名, ......>
typename和class后面的表示的是某种数据类型的形参名,将来在使用模板函数的时候传入自己指定的数据类型;而int和double后面的表示的是
这种数据类型的变量,将来在使用模板函数的时候自己传入自己的变量。所以对于模板的形参总共就是分为这两类:类型形参和非类型形参。
2、模板函数和模板类的使用
函数模板定义及其使用:
#include <iostream> using namespace std; template <typename T> // 声明函数模板 static T Add1(T a, T b) { return (a + b); } template <class T, int count> // 声明函数模板 static void Print(T a) { int i = 0; for (i = 0; i < count; i++) cout << a << " "; cout << endl; } int main(void) { cout << Add1<int>(10, 20) << endl; // 使用模板函数 Print<int, 5>(10); // 使用模板函数 return 0; }
类模板定义及其使用:
#include <iostream> using namespace std; template <typename T, int Ksize, int Kval> class Array{ public: Array(void); // 构造函数 ~Array(void) { delete[]p_Arr; p_Arr = NULL; } // 析构函数 类内定义方式 void display(void); private: T *p_Arr; }; template <typename T, int Ksize, int Kval> // 类外定义方式 Array<T, Ksize, Kval>::Array(void) { p_Arr = new T[Ksize]; int i = 0; for (i = 0; i < Ksize; i++) p_Arr[i] = Kval; } template <typename T, int Ksize, int Kval> // 类外定义方式 void Array<T, Ksize, Kval>::display(void) { int i = 0; for (i = 0; i < Ksize; i++) cout << p_Arr[i] << " "; cout << endl; } int main(void) { Array<int, 10, 10> arr; arr.display(); return 0; }
运行结果分别如下所示:
(1)对于模板函数的使用需要注意的是:我们需要在函数名之后添加一对尖括号,将需要传给函数模板的参数写进去: Add1<int>(10, 20);
但是其实不加 <int> 也是可以的,但是前提条件是函数的参数类型都是相同的,否则就会编译出错:
Add1(10, 20) // 这样是可以的,因为10 和 20 数据类型相同
Add1(10, 20.0) // 这就不行,数据类型不相同
(2)对于类模板需要注意的是:除了在类模板声明前加上 template <......> 之外,如果成员函数是在类内定义倒没什么可说的,如果是在类外定义的,那么就需要注意了:
每个在类外定义的所有成员函数之前都要加上 template <......>,而且函数名前面还要加上 <.....>,里面的内容是参数名,如下所示:
template <typename T, int Ksize, int Kval> // 类外定义方式
Array<T, Ksize, Kval>::Array(void) { }
(3)通过类模板来定义一个类对象的时候也是和函数差不多,也是需要加上 <...>,将要传给类模板的参数写进去即可: Array<int, 10, 10> arr;
2、模板本身不会占用内存空间,而定义的模板函数或者是模版类才会占用内存空间。
3、函数模板与同名非模板函数也可以重载。
#include <iostream> using namespace std; template <typename T> // 声明函数模板 static T Add(T a, T b) { cout << "模板函数" << endl; return (a + b); } static int Add(int a, int b) // 普通函数 { cout << "普通函数" << endl; return (a + b); } int main(void) { cout << Add(10, 20) << endl; return 0; }
运行结果如下:从结构可以看出来,函数模板与同名非模板函数也可以重载,而且当我们调用函数的时候优先调用的是普通的函数,而不是模板函数。
4、在template语句和函数模板定义语句之间是不允许插入其他的语句,并且一个 template<....> 只能对应一个模板的声明,而不用使用一个 template<....> 来声明多个函数模板或者是类模板。