admin管理员组

文章数量:1794759

c++基础篇(三)——模板初阶

c++基础篇(三)——模板初阶

作者介绍:

关于作者:东条希尔薇,一名喜欢编程的在校大学生 主攻方向:c++和linux 码云主页点我 本系列仓库直通车 作者CSDN主页地址

印刷术是中国四大发明之一,它极大地便利了古代人对于读书的需求。

设想,如果我们没有印刷术的话,我们要传播书籍该怎么做?我们必须要把这本书亲自手抄几万份后传播,这样的传播方式不仅非常的繁琐,而且浪费了很多不必要的人力

我们有印刷术就会方便许多,我们只需要抄一遍书上的内容,把它抄在一个模子上,然后使用这个模板,就能很轻松的把它复印几万份

而我们今天讲的内容,和古代的印刷术有异曲同工之妙

目录
  • 函数模板提出背景
  • 函数模板的概念与使用
  • 函数模板原理及其实例化
  • 类模板

函数模板提出背景

假如我们要实现一个函数,这个函数要实现两个变量的交换,我们可以轻松写出以下代码

void Swap(int& rx,int& ry) { int tmp=rx; rx=ry; ry=tmp; }

但这个函数会有一个问题:我们只能交换整数类型,那么我们要交换其它类型的数又该怎么办呢?

我们可能想到,把每个类型都写一遍不就行了?

void Swap(int& rx,int& ry) { int tmp=rx; rx=ry; ry=tmp; } void Swap(float& rx,float& ry) { float tmp=rx; rx=ry; ry=tmp; } void Swap(double& rx,double& ry) { double tmp=rx; rx=ry; ry=tmp; }

这样每个类型写一个函数,会造成大量的代码冗余,而且对于自定义类型,我们根本不能确定到底要写多少个这样的函数

所以,在c++里面引入了函数模板的概念

函数模板的概念与使用

函数模板代表了一个函数家族,该函数模板与类型无关,它会根据实参自动推导自己的参数类型

拥有模板也是c++能支持泛型编程的基础,它也是STL实现的基础

使用格式:

template<class T1,class T2,.....class Tn> //或者是typename T1.... //T1作为模板名,可以随意修改,不过一般都用T来表示

在上面一行代码完成后,下面要立即跟上一个模板函数

我们有了函数模板,就能让上面的swap函数支持任意类型,并且只有一份函数源码

template<class T> void swap(T& rx,T& ry) { T tmp=rx; rx=ry; ry=tmp; } 函数模板原理及其实例化

我们知道了函数模板能够实现所有类型的使用,那么函数模板算一个函数吗?

我们可以通过观察不同类型函数的地址来观察

观察其反汇编代码

我们可以观察到,每次调用函数时,对应的swap函数地址是不一样的

我们可以得出结论,模板函数并不是一个函数

函数模板需要通过实例化来让对应参数使用其函数

实例化:模板函数根据不同的参数类型,来推演出它的参数类型,然后专门处理出一个针对此类型的函数代码

而实例化方式分为两种:隐式实例化,显式实例化

隐式实例化

编译器根据实参,自动推导出参数的实际类型

template<class T> void Swap(T& x, T& y) { T tmp = x; x = y; y = tmp; } int main() { int a = 2; int b = 3; float c = 3.3f; float d = 4.4f; Swap(a, b); Swap(c, d); return 0; }

但注意:不能把不同类型的参数传入一个函数模板中,这样编译器就不知道这个模板到底推导成什么类型了

Swap(a,d);//int和float类型混合,报错

显式实例化

在函数名后加上**<类型名>**

Swap<int>(a,b); Swap<int>(a,d);//这里不同类型使用不会报错,而是会发生隐式类型转换为<>内的类型

实例化原则:

对于非模板函数和函数模板同名的情况,调用时如果类型与非模板参数完全相同,将会优先调用非模板函数

void Swap(int& x, int& y) { int tmp = x; x = y; y = tmp; } template<class T> void Swap(T& x, T& y) { T tmp = x; x = y; y = tmp; } int main() { int a = 2; int b = 3; float c = 3.3f; float d = 4.4f; Swap(a, b);//调用非模板 Swap(c, d);//调用模板 return 0; } 类模板

与函数模板类似,并不是一个真正的类型,而是根据不同类型推导出来的

使用方式:在类最上面使用template,类内部参数可以使用其模板

template<class T> class Stack//栈类 { public: void push(T n) { arr[top]=n; top++; size++; } private: T *arr; int tmp; int cap; }

注意以下几点

如果类成员函数在类外实现,必须要在每个函数前面加上template

类模板只能显式实例化

本文标签: 模板基础