C++——模板初阶
文章目录
- 一、前言
- 二、模板——初阶
- 2.1 再探重载
- 2.2模板使用的原理
- 2.3 模板的分类
- 2.3.1 函数模板
- 2.3.1.1 函数模板的概念
- 2.3.1.2 函数模板的格式
- 2.3.1.3函数模板的原理
- 2.1.3.4 函数模板的两种实例化方式
- 2.4 类模板
- 2.4.1 类模板的定义格式
- 2.4.2 类模板的实例化
- 2.5 模板参数的匹配原则
- 三、总结
一、前言
编程如同球场,唯有自己不断突破,才能取得最后的胜利
🚀鑫-萍的个人主页🚀
😀鑫-萍的Gittee仓库
🛬人生名言——与其被动迎敌,不如主动出击🛬
各位宝子们,今天是否又是活力满满的一天呢?学习之路有时候比较枯燥,所以我们更加要懂得如何放松自己,一味的盲目学习可是会适得其反的哦。一小碗鸡汤,先与大家共勉。好了,今天我们继续C++知识点的学习,今天要学习的内容是——模板初阶。
二、模板——初阶
2.1 再探重载
我们之前在学习函数重载的时候,会遇到这样一个问题——如何实现不同类型对象的Swap函数呢?
在一开始的时候,我们可能会这样来解决问题:
#include<iostream>
using namespace std;
void Swap(int& num1, int& num2)
{int tmp = num1;num1 = num2;num2 = tmp;
}
void Swap(double& num1, double& num2)
{double tmp = num1;num1 = num2;num2 = tmp;
}
void Swap(char& num1, char& num2)
{char tmp = num1;num1 = num2;num2 = tmp;
}
int main()
{int a1 = 1;int b1 = 2;cout << a1 << " "<<b1 << endl;Swap(a1, b1);cout << a1 << " " << b1 << endl;double a2 = 1.998;double b2 = 2.998;cout << a2 << " " << b2 << endl;Swap(a2, b2);cout << a2 << " " << b2 << endl;char a3 = 'y';char b3 = 'x';cout << a3 << " " << b3 << endl;Swap(a3, b3);cout << a3 << " " << b3 << endl;return 0;
}
这样的解决方法确实是实际可行的,但是现在虽然我们只有三种Swap重载,但是如果我们需要四种、九种甚至N种呢?要是按照之前的思路,一个一个地写重载函数,那整个工程的工程量未免太大了些。这时候有人会疑惑:有没有更加先进一点的方法呢?答案是肯定的。这时候模板的使用就可以通过一个泛型的模子来应对不同类型的实现需求。
#include<iostream>
using namespace std;
template <typename T>//定义一个模板
void Swap(T& num1, T& num2)
{T tmp = num1;num1 = num2;num2 = tmp;
}
int main()
{int a1 = 1;int b1 = 2;cout << a1 << " "<<b1 << endl;Swap(a1, b1);cout << a1 << " " << b1 << endl;double a2 = 1.998;double b2 = 2.998;cout << a2 << " " << b2 << endl;Swap(a2, b2);cout << a2 << " " << b2 << endl;char a3 = 'y';char b3 = 'x';cout << a3 << " " << b3 << endl;Swap(a3, b3);cout << a3 << " " << b3 << endl;return 0;
}
2.2模板使用的原理
经过两种不同方法的对比,我们更加实质上感受到的就是工程量的明显减少。那模板使用的原理又是什么呢?
在我们的陶瓷和手工业行业,就避免不了使用模具的情况,顾名思义,就是把你手上的材料导入一个固定的摸具之中,最后经过一系列加工,制作出外观与大小一致的样品。
那我们回到C++种,也会在这样的一个模具,通过给这个模具填充不同的类型的材料,来获得不同材料的铸件。
模板的使用是一种泛型编程。
泛型编程:缩写与类型无关的通用代码,是代码复用的一种手段。模板的泛型编程的基础。
2.3 模板的分类
2.3.1 函数模板
2.3.1.1 函数模板的概念
函数模板代表了一个函数家族,该函数的模板与类型无关,根据实参类型产生函数的特定类型版本。
2.3.1.2 函数模板的格式
template<typename T1,typename T2…。…typename Tn>
返回值类型 函数名(参数列表)[ ]
template //定义一个模板
void Swap(T& num1, T& num2) {
T tmp =num1;
num1 = num2;
num2 = tmp; }
注意:typename是用来定义模板的关键字,也可以使用class(但是不能使用struct来代替class)
2.3.1.3函数模板的原理
函数模板就如图一张修建房屋的工程图一样,它本身并不是函数,是编译器使用方式特定具体类型函数的模具,模板实际上把重复做的事情交给了编译器。
在编译器编译阶段,对于模板函数的使用,编译器需要传入的实参类型来推演生成的对应类型的函数。
2.1.3.4 函数模板的两种实例化方式
1、隐式实例化:让编译器根据实参推演模板参数的实际类型
2、显示实例化:在函数名<>中指定模板参数的实际类型
#include <iostream>
using namespace std;
template<typename T>
//类模板
class Stack
{
public:Stack(size_t capacity = 4){_arr = new T[capacity];_capacity = capacity;_size = 0;}void Push(const T& data){_arr[_size] = data;++_size;}
private:T* _arr;size_t _capacity;size_t _size;
};
int main()
{//Stack是类名,Stack<int>才是类型Stack<int> st1; //intStack<double> st2; //doublereturn 0;
}
2.4 类模板
2.4.1 类模板的定义格式
2.4.2 类模板的实例化
与函数模板实例化不同,类模板实例化需要在类模板名字后面跟<>,然后将实例化的类型放在<>中即可
注意:类模板名字不是真正的类,类模板实例化出来的结果才是真正的类·
2.5 模板参数的匹配原则
1、一个非模板函数和一个同名的模板函数同时存在,而且该函数模板还可以被实例化为这个非模板函数;
2、对于非模板函数和同名模板函数,如果其他条件相同,在调用时会优先调用非模板函数,但如果该模板可以产生一个具有更好匹配的函数,那么将选择模板;
3、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
#include <iostream>
using namespace std;
int Add(int num1, int num2)
{return num1 + num2;
}
template <typename T>
T Add(T num1, T num2)
{return num1 + num2;
}
int main()
{cout << Add(1, 2) << endl;//与非模板函数匹配,不需要编译器转化cout << Add<int>(1, 2) << endl;//与模板函数匹配,会调用编译器转化的版本cout << Add(1, 2.333) << endl;//模板函数可以生成更加适配的版本,编译器会调用模板函数cout << Add<double>(1, 2.333) << endl;return 0;
}
三、总结
到这里,大家应该了解了重载与模板之间的关联了吧。也不能说谁一定比谁好,不过是在特定的环境下选择更加优越的方法而已,大家在实际使用的时候也要注意这一点。最后,希望大家好好消化,好好复习,继续前进!