在我们学习C++时,常会用到函数重载。而函数重载,通常会需要我们编写较为重复的代码,这就显得臃肿,且效率低下。
重载的函数仅仅只是类型不同,代码的复用率比较低,只要有新类型出现时,就需要增加对应的函数。此外,代码的可维护性比较低,一个出错可能会导致所有的重载均出错。
那么,模板的出现,就让这些问题有了解决方案。
这里就不得不提及一个概念:泛型编程。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
而模板则分为函数模板和类模板。
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
这就是模板的常用格式。
typename是用来定义模板参数关键字,也可以使用class
T则是我们取的名字,也可以不叫T,取成任意名字(比如A)
//模板
template
template
template
下面是函数模板的一个简单应用。
template
T Add(const T& x, const T& y)
{
return x + y;
}
int main()
{
cout << Add(2, 3) << endl;
return 0;
}
但是,在使用函数模板时有几个点需要注意:
当传参类型不匹配时,可以采用显式实例化;
也可以使用强制转换,使得类型匹配。
template
T Add(const T& x, const T& y)
{
return x + y;
}
int main()
{
cout << Add(1.1, 2) << endl; //显式实例化
cout << Add((int)1.1, 2) << endl;
return 0;
}
当然是可以的。
并且,在调用时,若可以匹配上,则会优先调用它,而非使用模板生成。
template
T Add(const T& x, const T& y)
{
return x + y;
}
int Add(int x, int y)
{
return x + y;
}
int main()
{
cout << Add(2, 3) << endl;//不会使用模板
cout << Add(1.1, 2) << endl; //显式实例化
cout << Add((int)1.1, 2) << endl;
return 0;
}
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。
template
class 类模板名
{
// 类内成员定义
};
这是我们定义的一个栈。
template
class Stack
{
public:
Stack(int capacity = 4)
:_array(new T[capacity])
,_size(0)
,_capacity(capacity)
{
cout << "Stack()" << endl;
}
~Stack()
{
delete[] _array;
_size = 0;
_capacity = 0;
cout << "~Stack()" << endl;
}
void Push(const T& data)
{
if (_capacity == _size)
{
int newcapacity = _capacity == 0 ? 4 : _capacity * 2;
T* tmp = new T[newcapacity];
memcpy(tmp, _array, sizeof(T) * _size);
_array = tmp;
_capacity = newcapacity;
}
_array[_size] = data;
_size++;
}
private:
T* _array;
int _size;
int _capacity;
};
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
int main()
{
//Stack是类名,Stack才是类型
Stack st1;
st1.Push(1);
st1.Push(2);
st1.Push(3);
st1.Push(4);
st1.Push(5);
Stack st2;
st2.Push(1.1);
return 0;
}