C++入门之模板基础讲解
前言今天博主将要介绍的内容是–模板,他在C中具有非常重要的位置.至于什么是模板呢?我们请看下面的章节.引入我们对交换函数Swap已经非常熟悉了,但是我们经常会遇到这样的一些事,比如,很多不同的数据类型进行交换,那么我们就需要写不同的重载Swap,如下:1234567891011121314151617181920#include iostreamusingnamespacestd;voidSwap(int a,int b){intt a;a b;b t;}voidSwap(double a,double b){doublet a;a b;b t;}intmain(){inta 10,b 20;doublec 1.2,d 3.4;Swap(a,b);Swap(c,d);return0;}可以看到,如果有必要,我们需要交换几种类型的数据,就必须写上几种重载Swap,这就导致非常的繁琐,因为我们对其交换逻辑太熟悉了,只是换了变量类型,那有什么办法可以解决呢?没错,这就是我们今天要讲的模板.模板概念:在生活中,博主举一个例子,假设你是一个手办厂家,现在你需要售出各种材料和颜色做的悟空手办,首先你需要的就是悟空的模型,然后按照这个模型使用不同的材料.这个模型就是我们在程序中的模板.模板种类:函数模板类模板函数模板函数模板的格式:1234templateclassT1,classT2,...return_val function_name (para1,para1,...){}打省略号的都是形参列表,表示参数量自由,我们现在知道了怎样使用函数模板,那试试写一个Swap模板:1234567templateclassTvoidSwap (T a,T b){T t a;a b;b a;}按照模板规范,我们写出来了Swap的模板,现在测试一下结果是否正确呢?发现测试结果完全正确.然后这里博主有个疑问,就是我们调用Swap时,编译器是执行的上面模板呢?还是执行的通过模板推演出来的函数呢?答:通过模板推演出来的函数,因为C提出模板是为了节省程序员的时间,我们所省略的工作,只是编译器替我们完成了.也就是说,比如我们这样调用:123456intmain(){inta 10,b 20;Swap(a,b);return0;}那么编译器在底部会推演出一个如下函数,并执行:12345voidSwap(int a,int b){intt a;a b;b t;}模板的匹配原则什么叫做模板的匹配原则呢?就是说当既有定义出来的明确函数,同时又有模板,那么调用函数时候,执行的是哪一个?以下面为例:123456789101112131415161718voidSwap(int a,int b){intt a;a b;b t;}templateclassTvoidSwap (T a,T b){T t a;a b;b a;}intmain(){inta 10,b 20;Swap(a,b);return0;}匹配顺序为:如果有定义出来的函数,且类型完全匹配调用时实参类型,则执行定义出来的函数.如果定义出来的函数,不符合,则执行模板推演.也就是说,上面的例子中,Swap调用的是我们定义出来的Swap,而不是模板.模板的显示调用上面讲解的模板使用,其实被称做隐式调用,现在,博主介绍一下显示调用.显示调用格式:1functionType1,Type2,..(para1,para1,...);也就是说,我们明确知道需要使用的什么类型,并且就想告诉编译器,我传给你的是什么类型,然后让编译器推演出该类型的函数.比如下面使用:1234inta 10,b 20;charc a,d b;Swapint(a,b);//告诉编译器我传的是int类型Swapchar(c,d);//告诉编译器我传的是char类型大家可能会问了,这有什么用呢?既然编译器会根据我们的调用情况进行推演,还进行显示调用不是多此一举吗?大家请看下面的代码:1234567891011121314templateclassTvoidSwap (T a,T b){T t a;a b;b a;}intmain(){inta 10;doubleb 23.22;Swap(a,b);//这样调用编译器就会报错return0;}像上面的调用方式,是不允许的,因为模板中只有一个T,但是我们传了两个类型,编译器根据模板将不知道T应该是啥类型,而解决上面的问题只有两种一是强制性转换类型,比如Swap(a,(int)b);二是显示使用模板,比如Swapint(a,b);其次,博主讲解模板的显示调用还有一个目的就是为了引出下面的类模板.类模板类模板和函数模板相似,定义框架如下:1234templateclassT1,classT2,...classclass_name{};我们对数据结构—栈,应该算比较了解,而对于经常刷力扣的伙伴来说,可能会发现栈不只是用来存储int类型,比如还有ListNode*等,那我们大概写一下其stack模板吧.1234567891011121314151617templateclassTclassStack{public:Stack():data(newT*[10]),top(0),capacity(10) {}~Stack(){delete[] data;top capacity 0;}voidPush(T a){}private:T* data;inttop;intcapacity;};然后我们定义Stack对象,但是对象应该存储的类型是什么呢?如果我们继续用最开始的隐式模板方法,发现完全实现不了,这也就是博主上面为何要讲解模板的显示调用,因为类模板只能通过显示调用实现,例子使用如下:123Stack char st1;//定义一个存储char类型的栈Stack int st2;//定义一个存储int类型的栈Stack double st3;//定义一个存储double类型的栈Stack并不是类,其只是一个模板,Stack int等才是类注意1类模板只是一个模板,他并不属于类.