c++面向对象程序化设计的目标和重要特征之一就是实现代码重用,从而减少程序设计人员的工作量,如果要实现代码的可重用性,一般而言,代码必须高效,通用,不受数据类型与操作的影响,可适用于不同的情况,越通用性代码越支持可重用性,这种程序化设计称为参数化程序设计,模板是c++面向对象中支持参数化的重要工具,是更高一级抽象与参数多态的体现。
模板分为函数模板与类模板,但模板并不是通常意义上的可以直接使用的函数或者类,它仅仅是对一族函数或者类的描述,是参数化的函数和类。
函数模板:可以用来创建一个具有通用性的函数
定义格式:
template<模板形参表>
返回值类型 函数名 (参数表)
{
函数体;
}
我们在没有学习函数模板之前 用int与double计算相同的运算就必须写两个不同的函数
int abs(int a)
{
return (a > 0 ? a : -a);
}
double Max( double x,double y)
{
return (x > y ? x : y);
}
函数模板
template <class T> //一个参数
T abs(T a) //传参为模板参数,返回值为模板
{
return (a > 0 ? a : -a);
}
//当传参为int类型实例化后函数
int abs(int a)
{
return (a > 0 ? a : -a);
}
//当传参为double类型实例化后函数
double abs(double a)
{
return (a > 0 ? a : -a);
}
template <class T1,class T2> // 两个参数,类型可相同,可不同
T1 Max( T1 x,T2 y)
{
return (x > y ? x : y);
}
int main()
{
int x = 12;
double y = -15.6;
cout << abs(x) << " " << abs(y) << endl;
cout << Max(x, y) << endl;
}
函数模板是模板函数的抽象定义,不涉及具体的数据类型,而模板函数是函数模板的一个具体实例,是模板参数实例化后一个可执行的具体函数,在编译过程中,编译器会根据传递的参数类型 实例化出相对应的模板函数,编译器在调用时调用的是实例化后的函数,不同类型实例化后函数地址也不同。
类模板:与函数模板类似,类模板定义又关键字template引导(一个类模板的每个实例化都是一个独立的类)
template <模板形参表>
class 类模板名
{
成员函数;
}
类模板
template<class T> //可有不同多个的参数 ,每个都要用class或者typename 分离
class Square
{
public:
Square(T x)
:y(x)
{}
T fun() //成员函数类内定义
{
return y*y;
}
private:
T y;
};
int main()
{
Square<int> x(4.1);
square<float>y(16.5);
Square<double>z(15.55);
cout <<x.fun() << endl;
}
类模板实现简单顺序表:
#include <iostream>
using namespace std;
const int len = 16;
template <class T>
class Seqln
{
public:
Seqln<T>() //构造函数
: size(0)
{}
~Seqln<T>() //析构函数
{}
void print()
{
for (int i = 0; i < size; i++)
{
cout << arr[i];
}
cout << "\n" << endl;
}
void Insert(const T&m, const int pos); //数据类型为模板形参T
T Delete(const int pos); //返回值为模板形参T
int lnszie()const
{
return size;
}
private:
T arr[len];
int size;
};
//模板类的成员函数必须为函数模板
template <class T>
void Seqln<T>::Insert(const T&m, const int pos) //成员函数的类外定义
{
if (pos<0 || pos>size)
{
cout << "not error" << endl;
exit(1);
}
if (size == len)
{
cout << "this listis over" << endl;
exit(1);
}
for (int i = size; i > pos; i--)// 插入元素m
{
arr[i] = arr[i-1];
}
arr[pos] = m;
size++;
}
template<class T>
T Seqln<T>::Delete(const int pos)
{
if (pos<0 || pos>size-1)
{
cout << "not error" << endl;
exit(1);
}
if (size == 0)
{
cout << "list is null" << endl;
exit(1);
}
T temp = arr[pos-1];
for (int i = pos-1; i < size; i++)
{
arr[i] = arr[i + 1];
}
size--;
return temp;
}
int main()
{
Seqln<int> list;
list.Insert(3, 0);
list.Insert(1, 1);
list.Insert(2, 2);
list.Insert(3, 3);
list.Insert(4, 4);
list.print();
list.Delete(3);
list.print();
return 0;
}
模板编译:
通常我们调用一个函数时,编译器只需要掌握函数的声明,类似的,当我们使用一个类类型对象时,类定义必须是可用的,但成员函数的定义不必出现,因此我们可以将类定义与函数声明放在头文件中,而普通函数与与类的成员函数的定义放在源文件中
模板则不同,为了生成一个实例化版本,编译器需要掌握函数模板或类模板成员函数的定义,因此,与非模板代码不同,模板的头文件既包含声明也包含定义,不支持分离编译。
模板成员函数的实例化:
默认情况下,一个类模板的成员函数只有当程序使用的它时,才会将其实例化这一特性似的即使某种类型不能完全符合模板操作的要求,仍然可以使用实例化类。