个人主页
创作不易,感谢大家的关注!
🚀前言
模板可以分为两种,分别是函数模板和类模板。
⭐一、泛型编程
- 概念:编写与类型无关的通用代码,是代码复用的一个手段。模板是泛型编程的基础。
- 优点:当我们要交换函数时,我们可以使用函数重载的方式来进行实现,但重载的函数仅仅只是类型不同,代码的复用率较低。如果有交换函数的模板,我们就可以轻松解决多种类型之间的相互交换的问题。
🎡二、函数模板
1.概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
2.格式
template<typename T1,typename T2......typename Tn>
我们以交换函数来举例:
template<typename T>
void Swap(T& left, T& right)
{
T tmp = left;
left = right;
right = tmp;
}
通过上述代码,我们基本可以了解模板的使用。但需要注意的是:在定义模板参数关键字时,我们既可以使用template也可以使用class。
3.原理
函数模板其实是一个蓝图,它本身并不是函数,而是编译器的使用方式所产生特定具体类型函数的模具。换句话说,模板就是将本来应该我们做的重复的事情转交给了编译器。
注: 在编译器编译阶段,对于函数模板的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以提供调用。
4.实例化
- 定义:用不同类型的参数使用函数模板时,成为函数模板实例化。模板参数实例化可分为:隐式实例化和显式实例化。
- 隐式实例化的概念:让编译器根据实参来推演模板参数的实际类型。
- 显式实例化的概念:在函数名后加上<类型>来指定模板参数的实际类型。
template<typename T>
int Add(const T& a, const T& b)
{
return a + b;
}
int main()
{
int a = 10, b = 20;
int a1 = 1.0, b = 2.0;
//隐式实例化
Add(a, b);
//显示实例化
Add<int>(a1, b);
return 0;
}
5.匹配原则
1.一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。
3. 模板函数不允许自动类型转换,但是普通函数可以进行自动类型装换。
🏠三、类模板
1.定义格式
template<class T1, class T2, ..., class Tn>
class data(类模板名)
{
// 类内成员定义
};
2.实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,但类模板名字不是真正的类,而实例化的结果才是真正的类。
// Stack是类名,而Stack<int>才是类型
Stack<int> s1;
Stack<double> s2; //