模板是面向对象提搞效率一种方法,模板是对于一种功能相同,只是数据类型不同的不管是函数还是类,根据一个板子,然后刻出来!如:印刷书本,或者纸张,那些纸张都是一样的,不可能手写出来对吧,根据最开始的那个书本或者纸张,印刷出大量的书本或纸张!最开始的那书本或者纸张就可以称之为模板!模板又分为函数模板和类模板。
先来看交换函数,逻辑一样,只是形参类型不同,虽然它们构成函数重载,但是这些函数都需要写出来,降低了效率!
void Swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
void Swap(double x, double y)
{
double temp = x;
x = y;
y = temp;
}
void Swap(char x, char y)
{
char temp = x;
x = y;
y = temp;
}
交换函数它的功能都是交换两个数据,只是每次交换的这两个数据的类型可能不一样,如果像这样每次写出,很麻烦且还降低效率,可以写一个模板解决!
对于这种功能几乎一样,只是参数类型不同的,可以写成一个模板,这样的话每次使用的都是由这个函数模板生成的模具
模板关键字为template,模板参数关键字为typename/class
,后面是模板参数名,具体语句template
模板参数中,参数可以不止一个,可以有很多个模板参数!
template<typename T>//模板参数可以有多个,看自己需求
void Swap(T x, T y)
{
T temp = x;
x = y;
y = temp;
}
int main()
{
int a = 1, b = 2;
double d1 = 1.1, d2 = 2.2;
Swap(a, b);
Swap(d1, d2);
return 0;
}
而当去调用时,并不是调用的同一个函数,而是调用由模板实例化生成具体的函数
这两个个调用的并不是同一个函数,而是由模板实例化生成的对应实参类型的具体类型的函数,然后再去调用实例化出的函数
像这种函数调用,函数模板根据调用,编译器会自动推导模板参数的类型,实例化出对应的函数,而这样的实例化也叫做隐式实例化
模板实例化
模板实例化:隐式实例化和显示实例化
当隐式实例化无法满足时,需要具体显示写出模板参数类型,无法完成自动推导,需要自己写出具体类型,如有些时候函数形参不是模板参数而
返回值类型是模板参数类型时,此时就需要显示实例化了,编译器无法自动推导模板参数的类型
template<class T>
T* Alloc(int n)
{
return new T[n];
}
int main()
{
Alloc<int>(10);
return 0;
}
显示实例化是:函数名/类名<类型>
以栈为例
一般的栈类
typedef int DataType;
class Stack
{
public:
Stack(int capacity = 4)
:_array(new DataType[capacity])
,_capacity(capacity)
,_top(0)
{
cout << "Stack(int capacity = 4)" << endl;
}
~Stack()
{
if (_array)
{
delete[] _array;
_array = nullptr;
_capacity = 0;
_top = 0;
}
cout << "~Stack" << endl;
}
private:
int* _array;
int _capacity;
int _top;
};
这是一个存储int型数据的栈类,如果要存储double,float…但是它们功能的实现又是一样的,如果还是这样写效率底且麻烦,并且如果其中有bug的话,那么所有栈都要修改,这样直接哭死,写一个类模板
template<class T>
class Stack
{
public:
Stack(int capacity = 4)
:_array(new T[capacity])
, _capacity(capacity)
, _top(0)
{
cout << "Stack(int capacity = 4)" << endl;
}
~Stack()
{
if (_array)
{
delete[] _array;
_array = nullptr;
_capacity = 0;
_top = 0;
}
cout << "~Stack" << endl;
}
private:
T* _array;
int _capacity;
int _top;
};
int main()
{
Stack<int> st1;
Stack<double> st2;
return 0;
}
这样它只是存储数据的类型不同,有什么问题直接在类模板修改即可!
但是类模板的实例化,只能显示实例化,并没有隐式实例化,因为有些数据会在类成员函数中或者其它位置,当类模板需实例化对象时需指定实例化类型!
但是类模板又不同于普通类
普通类:类名就是类型
类模板:类名是类名,类型是类名<模板参数类型>
所有类中声明和变量分离,指定类域都是要类模板显示实例化的!如:
template<class T>
class Stack
{
public:
Stack(int capacity = 4);
~Stack();
private:
T* _array;
int _capacity;
int _top;
};
template<class T>
Stack<T>::Stack(int capacity )
:_array(new T[capacity])
, _capacity(capacity)
, _top(0)
{
cout << "Stack(int capacity = 4)" << endl;
}
template<class T>
Stack<T>::~Stack()
{
if (_array)
{
delete[] _array;
_array = nullptr;
_capacity = 0;
_top = 0;
}
cout << "~Stack" << endl;
}
且每一个模板惨呼它的作用域是在它那个函数模板或者类模板,不会越界!
结束!