- 什么泛型编程,模板
- 函数模板
- 类模板
- 什么是泛型编程
怎样去用一个函数去int交换数据,也许你会说这是如此的so easy,你看我的
void swap(int &a,int &b){
int c = a;
a = b;
b = a;
}
这不就写好了吗,但是如果让你写一个double类型的交换函数呢,你可能也会说简单,但是实现一个函数交换自定义类型呢,没办法了吧!!因为自定义类型有无数种,不可能实现无数种的函数吧,这里我们就需要使用泛型编程,这里交换的函数功能相同,但是减缓的类型不一样,我们能不能传递一个通用的类型让编译器自己去识别类型呢?泛型编程就是这样的,只是给编译器一个模板,让编译器自己去识别类型。这也就是模板,就是编写与类型无关的通用代码,是代码复用的手段。模板就是我们在泛型编程的基础上进行的。
- 函数模板
-
什么是函数模板
顾名思义就是函数模板就是提供一个模板,代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生的特点类型版本 -
函数模板格式
template<class T1,class T2…>
返回值类型 函数名(参数列表)
例如
template<class T>
void Swap(T& a,T& b){
T c = a;
a = b;
b = c;
}
这就实现了所有交换函数。
这里class可以被typename替换,但是在调用的时候我们是调用的函数模板吗?
- 模板函数实现原理
在我们调用的时候不是调用的函数模板,而是在我们调用函数模板的时候编译器会根据我们的参数类型生成对应的函数,根据生成的函数根据我们的函数重载就可以找到我们符合类型的函数
模板就是一个蓝图,他本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具,在我们调用函数模板的时候编译器要根据传入的实参类型来推演生成对应类型的函数以供调用。比如我们上图中调用double类型使用函数模板时,编译通过对应实参类型进行推演。
看下面代码是否能编译运行
#include <iostream>
using namespace std;
template <class T>
void Swap(T &a, T& b){
T c = a;
a = b
b = c;
}
int main(){
system("pause");
return EXIT_SUCCESS;
}
答案是能通过编译以及运行,在我们代码中含有函数模板时我们只是在使用的时候才会进入到我们的函数模板中检查错误,但是模板函数该有的代码块是不能少的,就是{}是不可或缺的。
- 函数模板的使用
- 隐式实例化
在使用函数模板的时候不指定类型,比如我们上边的代码Swap(4,5);
。就是隐式实例化
template<class T>
void Swap(T& a,T& b){
T c = a;
a = b;
b = c;
}
int main(){
Swap(4,5);
return 0;
}
- 显示实例化
在函数名后的<>中指定模板函数的实际类型
比如Swap<int>(4,5);
template<class T>
void Swap(T& a,T& b){
T c = a;
a = b;
b = c;
}
int main(){
Swap<int>(4,5);
return 0;
}
模板参数的匹配原则
- 一个非模板函数和一个同名的模板函数同时存在,而且该函数模板可以实例化成这个非模板函数的时候选择非模板函数。
- 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模 板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
- 模板函数不允许自动类型转换,但是普通函数可以进行自动类型转换
类模板
类模板和函数模板类似,都是为了实现某一些类,这些类功能相同,但是数据参数不同
比如我们的字符串类和int型的数组
- 类模板的定义
template <class T1,class T2....>
class 类模板名{
//类成员
};
比如我们的顺序表,顺序表是可以存储任何数据类型,只是存储数据类型不同。
template <class T>
class Vector{
public:
Vector(){};
~Vector(){};
void Push_back(){const T& data};
....
private:
T* _p;
size_t _size;
size_t _capacity;
};
这里我们的Vector不是一个类,就和我们的模板函数不是一个函数一样,Vector是一个容器,只是一个存储数据的模板。
- 类模板的实例化
类模板实例化需要在类模板后面加上<>,在<>中加上数据类型,
例如std::vector<int>
#include <iostream>
using std::cout;
using std::endl;
int main(){
std::vector<int>v;
v.push_back(1);
v.push_back(2);
return 0;
}
在我们对类模板初始化之后就可以进行使用此v进行操作。
理解我们的Vector
和Vector<int>
之间的关系