👍作者主页:进击的1++
🤩 专栏链接:【1++的C++初阶】
文章目录
- 一,浅谈模板
- 二,函数模板
- 三,类模板
一,浅谈模板
在前面的文章【【1++的C++初阶】之C++入门篇1】中我们对函数重载有了一定的认识,函数重载有一定的好处,但其也有一些不足之处,例如,代码复用率低;可维护性不好。而模板能解决这种情况。模板就像工厂里 的摸具一样,对一些构造基本相同的产品能够加快其生成速率,可维护性也增加,产品出问题,只需去调整摸具。同样的,在编程中叫做泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
二,函数模板
什么叫函数模板?
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
函数模板的格式:
template<typename T1, typename T2,…,typename Tn>
返回值类型 函数名(参数列表){}
注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)
看下面这段代码:
template<typename T1,typename T2>
void Swap(T1& a, T2& b)
{
T1 tmp = a;
a = b;
b = tmp;
}
void Test1()
{
int a = 2;
short b = 48;
float c = 1;
Swap(a, c);
Swap(a, b);
cout << a << endl << b << endl << c << endl;
}
int main()
{
Test1();
return 0;
}
运行结果:
在这段代码中我们可以非常明显的看出,模板解决了上述函数重载中的不足 。
函数模板的实质:函数模板并不是函数,是编译器用来产生特定具体类型函数的摸具。有了模板后我们以前写函数重载时的一些重复动作就都交给了编译器。
接下来,我们谈谈,编译器遇到函数模板后是怎么做的?
我们以上述代码为例,在编译阶段,对于模板函数编译器会根据我们传过去的实参类型而推导出并生成对应类型的函数。
使用函数模板的过程我们称为函数模板的实例化,实例化有两种,一种是隐式实例化,另一种是显式实例化。隐式实例化:根据实参推演出函数模板参数的类型。
以以下代码为例:
void Swap(T1& a, T2& b)
{
T1 tmp = a;
a = b;
b = tmp;
}
void Test1()
{
int a = 2;
short b = 48;
float c = 1;
Swap(a, c);
Swap(a, b);
cout << a << endl << b << endl << c << endl;
}
但隐式实例化需要注意一些东西!
再来看一段:
template <class T>
T Add(T a, T b)
{
return a + b;
}
void Test2()
{
int a = 1;
int b = 2;
float c = 3;
short d = 4;
Add(a, b);//成功运行
Add(a, c);//报错,编译错误
}
在这段代码中,我们看到,编译器在通过实参推演的时候a将T推演为int,c将T推演为float,因此就会产生错误。解决这种错误有两种方法,一种是在传参时进行强制转换,保证其类型相同,另一种则时进行显式实例化。
代码如下:
T Add(T a, T b)
{
return a + b;
}
void Test2()
{
int a = 1;
int b = 2;
float c = 3;
short d = 4;
Add(a, b);//成功运行
cout << Add<int>(a, c) << endl;//显式实例化
}
注意:模板函数不能够使用自动类型转换
三,类模板
类模板的格式;
template<class T1, class T2, …, class Tn>
class 类模板名
{
// 类内成员定义
};
来看代码:
template <class T>
class Vector
{
public:
Vector()
{
_size = 0;
_capacity = 4;
_data = new T[4];
}
~Vector()
{
delete[] _data;
_size = 0;
_capacity = 0;
}
void push(T x);
private:
int _size;
int _capacity;
T* _data;
};
//注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
void Vector<T>::push(T x)
{
delete[] _data;
_size = 0;
_capacity = 0;
}
void Test3()
{
Vector<int> L2;
L2.push(1);
L2.push(2);
Vector<float>L3;
L3.push(3.0);
}
类模板名字不是真正的类,而实例化的结果才是真正的类。