思考:为什么要引入模板呢?

对于这个问题,我们通过一个例子让大家切实体会一下,模板给我们带来的好处。

当我们要写一个比较大小的函数时,如果我们要比较的两个数是整数,那么,我们往往会这样来定义:

首先,传入两个int类型的参数a和b,然后去比较a和b的大小,将较大的数通过return返回出来,使它成为max这个函数的返回值。

可是,如果我们又想比较两个float类型的数,那么这两个数也要取其中的最大值,那么,我们可以写成这样:

同样的,如果我们要比较两个char类型的字符呢,那么,我们就可以写成这样:

通过上面的三个函数,大家可以看到,除了数据类型有所不同之外,它们的运算逻辑是完全相同的。那么,在这种情况下,大家会发现,如果我们要写上这三个函数,对于我们程序员来说,简直太痛苦,而且所做的工作重复性较高,没有多大意义。所以,这种情况下,最好有一种方案:将类型作为参数传递进去,通过计算机帮我们把这三个函数做出来,做出来之后就可以分别通过这三个函数来处理int类型,float类型、char类型的数据,并且能够根据传入的数据类型做相应的处理,从而得到相应的返回值,于是,作为程序员的我们就省事多了。

那么,如果想要这么做,我们需要学习三个关键字:template(模板)、typename、class(注意:这里的class不是表示类的,而是表示数据类型的)。我们来看一看具体的使用方法。

我们看到,当我们要定义一个函数模板的时候,我们需要通过关键字template来声明一个函数模板,通过class或者typename这个关键字来声明一个参数T,这个参数T能够表明一种数据类型。如果我们再去写max这个函数的时候,它的返回值就写上T,它的参数类型也用T来作参数类型,并且函数内部逻辑不变。于是,当我们未来要传入的是int类型的时候,计算机就会通过这个函数模板将它实例化一个模板函数,这个时候模板函数中的数据类型T就变成了int,就会去处理int类型的数据了。如果遇到的是float类型,T就变成了float,然后也就会去处理float类型的数据了。我们来看一看具体的使用。

当我们用max去比较两个数的大小的时候,如果我们不指定它的数据类型T,那么,计算机会根据自己的判断去选择一种模板函数,选择之后就会用自己的计算逻辑,比如说这里的第一行代码,传入的100和99都是int类型的,它就会自动实例化一个int类型的模板函数,然后对100和99进行相应处理,并将处理互殴的结果100返回出来作为返回值赋值给ival。如果我们制定了数据类型,比如说这里的第二行代码,同样是调用max函数,但是这里用了一对尖括号指明了数据类型为char类型,那么,这就指定了所传入的参数一定要是char类型的参数才可以,然后将返回值返回出去。

那么,我们上面所说的模板函数和函数模板,我们给大家指出来,如下所示:

函数模板是函数的模具,通过模子就可以生产出一个一个的函数,那么,通过函数模板生产出来的函数就称之为模板函数。在计算机当中,如果我们仅仅写出了函数模板而没有去使用它,那么,计算机是不会产生任何代码数据的,因为它也不知道要产生什么样的代码数据。只有当我们去使用函数模板的时候,计算机才会知道具体要实例化出一个怎样的模板函数来,这个时候才会产生真正的代码数据,从而才会参与逻辑运算。

下面我们来看一看通过关键字typename如何来定义一个函数模板。

以上是一个数据交换的函数,在使用上没有什么不同,我们可以看到:当我们调用swap函数的时候,我们所传入的参数是int类型,这就意味着前面的数据类型T就替换成了int。

变量作为模板参数

变量作为模板参数如何来使用呢??我们直接来看使用的方法:

这里通过关键字template声明了一个函数模板,注意,这个时候传入的不再是类型,而是一个变量,而这个变量在我们真正去使用的时候才会将这个函数模板实例化成一个模板函数,它才是一个确定的值,如果不使用它,仍然是没有任何代码数据产生。使用的时候,我们在这传入的不是类型,而是一个确定的数值,此时这个值就是一个常数,只不过在这体现出来的看上去像是一个变量,但真正编译出来就是一个常数。

多参数函数模板

模板有的时候变得很复杂,因为我们不能确定,在我们的日常应用当中只有一个类型作为模板的参数,如果有多个参数我们该如何去处理呢?我们来看一看:

我们看到,当有多个参数时,需要用逗号(,)隔开,并且,尖括号中的两个typename关键字是不能省略的。当我们写成这样之后,T和C就变成了函数模板的参数,那么,在display函数中,其中一个参数a是T类型的参数,另一个参数b是C类型的参数。使用的时候,我们需要将T类型和C类型都指定出来,如下:

在这我们调用display的时候,就爱那个int类型作为第一个参数,将string类型作为第二个参数

注意:typename和class这两个关键字可以混用,它们所起的作用是一样的。如下所示:

我们还可以这样来混用,如下所示:

在这里,用typename哎定义了一个数据类型T,另外一个则是int类型的变量size。我们在使用的时候,就可以制定出size的值以及T的数据类型,如下:

这里调用display的时候,第一个传入的参数是int类型,即用int代替了上面的T,第二参数是5,即用5代替了上面的size,打印的效果就是打印出5个a。

函数模板与重载

其实函数的模板看上去就已经具有重载的意思了,因为通过函数的模板可以拓展出无数个模板函数来,我们可以尽情的去想象它能够拓展出来的数据类型,那么,这些拓展出来的模板函数之间就能形成了一种重载关系。此外,不同的函数模板所拓展出来的模板函数也能够形成重载。我们来看一看:

上面这三个函数的模板骑士都有所不同。第一个函数模板只有一个参数a,第二个函数模板有两个参数a和b,那么第一个与第二个就形成了参数个数不同的函数重载关系。第三个函数模板也只有一个参数,看上去与第一个函数模板一样,但是,第三个函数模板,它的模板参数本身就有两个:一个是T类型,一个是int类型的size变量,那么这个时候当我们去使用的时候:

你会发现,通过三个不同的函数模板可以实例化出三个不同的模板函数,这三个不同的模板函数之间就形成了重载关系。大家请注意:我们在定义出函数模板的时候,函数模板本身并不是互相重载的关系,因为当我们仅仅定义出函数模板,在内存当中并不会产生任何的数据代码,只有当我们去使用它的时候,编译器才会为我们产生出相应的函数代码出来,这些函数代码之间才可以称得上具有重载关系。

类模板

为什么会有类模板呢?这和函数模板的道理是一样的,是因为在很多使用场合下,一个类会用到很多次,而在用的时候发现很多重复的地方,只有它的数据类型不同,所以这个时候我们就要用到类模板。我们看下面一个例子:

在这里,我们定义了一个类:MyArray,其中,我们用T这种数据类型来定义了它的数据成员的指针,并且还定义了一个成员函数display,请大家注意,这个成员函数的定义时写在类内的。那么在类模板的情况下,在类内定义成员函数的时候并没有什么不同。但是,在类模板的情况下,在类外定义成员函数的时候,则大不相同,如下:

我们看到,在类模板的情况下,当在类外定义成员函数的时候,需要在这个成员函数的上方,先把template <class T>这一行代码写出来(注意,它的写法与在类的上方的写法是一样的),我们每定义一个成员函数,都要在这个定义的成员函数上方加上这一行代码;同时,我们需要在这个成员函数的类名后面用尖括号括上相应的参数T(如果有两个参数,需要用逗号隔开)。在使用的时候,我们如果实例化一个对象,我们就需要在类名的后面用尖括号括上当前这个对象是什么数据类型。

与函数模板一样,类模板并不产生实质性代码,只有当我们去实例化一个对象时,将类的后面写上一个固定的参数,这个时候才会产生数据代码,而这套数据代码,我们就称之为模板类,那么,这样的关系与前面所讲的函数模板与模板函数的道理一样。

下面我们来看一看,类模板当中使用多个参数的情况。当我们有多个参数时,我们举了一种比较复杂的情况(既有类型作为参数,也有变量作为参数)如下:

使用的时候,也分为类内定义和类外定义的成员函数。对于类内定义,我们不必多说了,而对于类外定义,如下:

在使用的时候,我们同样也要给定两个参数,如下:

需要大家特别注意的是:如果我们要定义一个类模板,我们必须将类的声明以及类的定义部分写在同一个.h文件当中,未来在使用的时候把它包含进来,所以在MyArray.cpp文件当中没有写任何代码,而是将所有代码都写在了MyArray.h文件当中了。

另外,定义类模板的时候,还需要注意以下内容

  • 在类的上面一行,要写上template关键字,然后加上模板参数列表;
  • 如果我们在类的内部定义函数时(类内定义),那么,我们不需要有什么特别需要注意的地方;
  • 如果我们在类的外部定义函数时(类外定义),则需要在每一个函数的上面加上template关键字,然后再加上模板参数列表。另外,在函数定义时,还需要用尖括号括上相应参数。
#ifndef TEMPLATE_H
#define TEMPLATE_Htemplate <typename T, int size ,int value>//类模板
class Template
{
public:Template();~Template();void display();
private:T * m_pArr;//类模板里的参数
};template <typename T, int size ,int value>//模板类的每个成员函数都要以模板的形式呈现
Template<T,size,value>::Template(){//模板类的每个成员函数都要以模板的形式呈现m_pArr = new T[size];//创建类型为T的size个数组,赋值给指针for(int i = 0; i < size; i ++){m_pArr[i] = value;//所有赋值为value}
}template <typename T, int size ,int value>
Template<T,size,value>::~Template(){//模板类的每个成员函数都要以模板的形式呈现delete []m_pArr;m_pArr = NULL;
}template <typename T, int size ,int value>
void Template<T,size,value>::display(){//模板类的每个成员函数都要以模板的形式呈现for(int i = 0;i < size; i++){cout<<"value :"<<m_pArr[i]<<endl;}
}#endif // TEMPLATE_H
#include <iostream>
#include "template.h"
using namespace std;int main()
{Template<int,10,5> tmp;tmp.display();getchar();return 0;
}

C++模板函数 模板类相关推荐

  1. 关于模板函数/模板类编译成DLL

    ]关于模板函数/模板类编译成DLL Posted on 2011-08-16 08:48 单鱼游弋 阅读( 353) 评论( 0) 编辑 收藏 要编译成DLL,就要声明和实现分开. 首先文件组织是这样 ...

  2. C++函数模板和模板函数、类模板和模板类

    这期间有涉及到函数模板与模板函数,类模板与模板类的概念 (类似于类与类对象的区别) 注意:模板类的函数声明和实现必须都在头文件中完成,不能像普通类那样声明在.h文件中,实现在.cpp文件中. 1.函数 ...

  3. 笔记②:牛客校招冲刺集训营---C++工程师(面向对象(友元、运算符重载、继承、多态) -- 内存管理 -- 名称空间、模板(类模板/函数模板) -- STL)

    0618 C++工程师 第5章 高频考点与真题精讲 5.1 指针 & 5.2 函数 5.3 面向对象(和5.4.5.5共三次直播课) 5.3.1 - 5.3.11 5.3.12-14 友元 友 ...

  4. C++中模板类中的成员函数以及模板函数在类外定义

    在C++中,类中的成员函数可以在类外完成定义,从而显得类中的成员函数看起来简洁明了.但是模板类里的成员函数和模板函数与普通的成员函数在类外定义不同. 先定义一个模板类以及成员函数和模板函数: 接下我们 ...

  5. 【C++】模板-函数模板、类模板

    文章目录 泛型编程 函数模板 函数模板的原理 函数模板的实例化 模板参数的匹配原则 类模板 类模板的定义格式 类模板的实例化 泛型编程 如果我们想要实现一个通用的交换函数,我们可以通过函数重载来实现, ...

  6. 类模板函数模板从属类型

    准备看个项目找实习,边看边学,一看到处都是template 和typename,好几年前学的C++都忘记光了,在这里先做个笔记复习一下. template <class T> T abs( ...

  7. C++笔记7:C++提高编程1:模板—[函数模板和类模板]

    0820 C++提高编程: 1.模板-[函数模板和类模板] 2.初识STL 3.STL-常用容器 4.STL-函数对象 5.STL-常用算法 C++提高编程引言: C++除了面向对象编程思想,还有泛型 ...

  8. 泛函编程—模板函数_类模板

    函数业务逻辑一样,只是函数参数类型不同 函数模板的本质:类型参数化--泛型编程 语法: template <typename T> template <class T1,class ...

  9. 8-1日复习 模板函数 模板类

    函数的重载: //函数重载 感觉还是太繁琐 引入函数模板的概念#include <iostream>using namespace std;int add(int x , int y) { ...

  10. java定义类模板_定义模板——函数模板和类模板

    面向对象编程(OOP)和泛型编程都能处理在编写程序时不知道类型的情况.不同之处在于:OOP能处理类型在程序运行之前都未知的情况:而在泛型编程中,在编译时就能获知类型了. 前面介绍的容器.迭代器和算法都 ...

最新文章

  1. 奖励名单表格模板_员工出勤工薪记算表(行政人事模板)
  2. win7启动后报丢失nscmk.dll解决解决方式
  3. SCCM2012 RBA
  4. vbn中使用的3种流程控制结构是_细菌进化树构建:从模式种序列下载到构建系统发育树一键搞定...
  5. 判定重大风险有哪几种_化工生产安全管理信息化平台可以解决哪些重大问题
  6. Lync 服务器证书 ios,iOS生成服务器所需证书pem或P12
  7. 禅道 bug状态 open_小工具大帮手,利用 @open-node/antman 实现 node.js 进程线上调试,无须重启...
  8. 循环录(输)入 java 课的学生成绩(5个学生),统计分数大于等于 80 分的学生
  9. “乘风破浪”的中国SaaS :风浪越大,机会越大?
  10. 计算机主板型号进bios,什么是BIOS?
  11. border_mode
  12. 已知p是一个指向类a的数据成员m的指针_C++ this指针的理解和作用
  13. C# MysqlHelper 执行reader时,遇到致命错误或者超时
  14. Delphi7中idhttp和superobject获取网页中文乱码解决办法
  15. CAD图纸管理用什么软件?
  16. Python处理Excel数据-pandas篇
  17. HTML学生个人网站作业设计——HTML+CSS+JavaScript简单的大学生书店网页制作(13页) web期末作业设计网页 web结课作业的源码 web网页设计实例作业
  18. [渝粤教育] 郑州工程技术学院 食品微生物学 参考 资料
  19. 一生至少原谅的三个人
  20. 【CozeTalk】如何衡量你的人生-人生修炼手册-克莱顿·克里斯坦森

热门文章

  1. 10秒钟,chatgpt帮你生成简单贪吃蛇游戏
  2. jquery 竖向实现组织结构图,自定义样式
  3. 特殊字符200b200c200d的删除办法与原理
  4. Word、Excel组合 批量打印信封
  5. Linux容器技术进化史
  6. Opera浏览器抽疯,点击后可响应,可在任务栏显示缩略图,但无法在桌面显示的解决方案及书签文件查找
  7. 精通Linux的“kill”命令
  8. oralce企业版的安装和卸载
  9. 一大波新款iPhone跟安卓厂商抢夺5G市场
  10. 网络编程flask一些学习笔记摘抄(一)