🌟 各位看官好,我是egoist2023!
🌍 种一棵树最好是十年前,其次是现在!
🚀 今天来学习模板的相关知识,有了模板之后就能大大提高效率。
👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦!
目录
引入
泛型编程
函数模板
概念
格式
原理
函数模板实例化
匹配原则
引入
类模板
定义格式
类模板实例化
引入
泛型编程
在如上一段代码中,写了一个Swap函数,为了多种类型的支持,因此通过函数重载达到了多种类型的变量的交换。但是,如果此时增加一个新类型:如float类型或者类类型时,又需要程序员再增加自己对应的的函数。
- 这是非常麻烦且代码复用性较低。每当出现新类型,都需要手动增加新函数;
- 代码的维护性低,一旦某个位置出错,其余的函数重载都得改动。
很显然,这种方式不是我们所期望的。那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?
函数模板
概念
格式
小编带着瞅瞅stl模板库中基本都是模板来实现的。
从这里就可以发现模板的妙处,编译器能通过我们写的变量自动推导类型,生成不同的函数。那模板的格式又是咋样的呢?
//template<typename T>
template<class T>
void Swap(T& left, T& right)
{T temp = left;left = right;right = temp;
}
原理

函数模板实例化
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 20;double d1 = 10.0, d2 = 20.0;Add(a1, a2);Add(d1, d2);return 0;
}
这里的报错信息是未找到匹配的重载函数,为什么呢?
- 自己手动强转从而来匹配对应的重载函数;
- 使用显式实例化。
Add<int>(a, b);
匹配原则
1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这 个非模板函数。2.对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而 不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。(即编译器有现成的会吃现成的,不会去推演)那如果非要调用模板函数呢?使用显式实例化。int Add(int left, int right) {return left + right; }template<class T> T Add(T left, T right) {return left + right; }Add(1, 2);
3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
前言
在实现顺序表、链表等数据结构时,我们常常使用
typedef + 类型 + 命名;
但是这种只能支持一种类型,即类型如果写成int,就只能插入int类型的数据;如果写成double类型,就只能插入double类型的数据。有没什么方法可以让这个类实现多个类型呢?那就需要引入类模板的概念。
类模板
定义格式
template<class T1, class T2, ..., class Tn>
class 类模板名
{// 类内成员定义
};
// 类模版
template<class T>
class Stack
{
public:Stack(size_t capacity = 4){_array = new T[capacity];_capacity = capacity;_size = 0;}void Push(const T& data){//...}
private:T* _array;size_t _capacity;size_t _size;
};
在上面一段程序中,写了一段Stack类模板,可以支持多种类型的类。表面上看,我们只写了一份类模板,但实际编译器需要根据不同类型生成不同类型的类。这种方式极大减少了程序员敲代码的痛苦,脏活累活都交给了编译器来处理。
并且,模板并不推荐声明和定义分离到两个文件.h 和.cpp,这样会出现链接错误。(后续会讲)
类模板实例化
// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double