Ⅰ、什么是模板?
我们在C++中可以对函数进行重载,但对于不同类型变量还是要写对应的函数这样还是很麻烦,比如Add函数我们如果要实现对int类型的相加我们要实现Add(int a,int b),如果我们还要对double类型的相加我们还需要写一份Add(double a,double b),这两个函数的逻辑相同只是在参数列表中的形参类型不一样有没有什么办法可以让我们实现复用这样就可以减少我们的工作量。
这时模板就可以很好的帮我们解决这个问题。模板可以提高代码的复用率还可以帮助我们实现泛型编程。下面图展示了类的分类。
Ⅱ 、函数模板
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
template<class T>
T Add(T a, T b)
{
return a + b;
}
int main()
{
int a = 10, b = 20;
cout << Add(a, b) << endl;
return 0;
}
上面就展示了一个用模板函数去写Add实现相加,template(模板的意思)是一个关键字,模板定义是从template开始后面跟一个模板参数列表(<class T>)classT是模板参数。
当我们调用Add函数时候编译器会根据我们的传参来推断class T的类型确定T是什么类型后编译器会生成对应的函数,如果无法推到出编译器会报错。
一、编译器无法确定类型
传入两个不一样类型的实参,当编译器遇见a时会认为T是int类型的但当遇见b时b是double类型的编译器就会不知道T到底是上面类型的这是就会报错。
要解决这个问题有三个方法:
方法一:将b强转成int类型这样两个都是int类型的编译器就不会报错
方法二:将a强转double类型
这个方法和上面方法一一样把一方强转让编译器可以明确T的类型
方法三:显示实例化:在函数名后面加<>在里边指定模板参数的实际类型
这样相当于告诉编译器T是什么类型的编译器就不用通过a和b来推断T的类型
总之,一定要让编译器明白模板参数的实际类型。
注意:方法一和方法二编译器推断出的Add是两个不同的函数并不是一个!
这里两个函数的地址不是一个
四、函数模板和普通函数的调用规则
规则1:函数模板和普通函数都可以调用,优先调用普通函数;
规则2:我们可以加上空的模板参数列表强制调用函数模板,即函数调用时后面加上尖括号(Add<>(a, b));
规则3:函数模板可以发生重载,即不同模板函数名可以一样;
规则4:如果有更好的匹配,编译器也会根据更好匹配优先调用函数模板;
Add(a1, a2)当没有强制调用模板函数是的时候编译器在具体函数和模板函数之间选择具体函数因为编译器如果用模板函数生成对应的函数和具体的函数是一样的所以编译器不会调用模板提升效率。
Add<>(a1, a2)当在函数名后面加上<> 的时候编译器就会强制调用模板函数。
Add(a2, b2) a2和b2不是同一种类型的但我们提供了有两个类型的模板参数列表编译器会选择最适合的模板函数而不会报错了。
T2 Add(T1 a, T2 b)和T Add (T a,T b)形成了函数重载。