假如我们需要取得两个变量中较大的变量,或许,我们可以通过重载的方式实现,如下。

int max(int fir,int sec);
float max(float fir,float sec);
double max(double fir,double sec);

有一天,我们定义了一个新的type,School,取决于max的实现,我们不仅需要重载School::operator<(), 或者School::operator>()还要重载一个新的max

const School max(School& fir,School& sec);

使用C++的模板,从此告别这些繁琐而又略显臃肿的代码。

注:1. 上述的返回值可以考虑使用const School&,但一般不建议,参见在返回值拒绝reference
2.形参使用了School&,参见传参时,使用引用替换变量

函数模板

顾名思义,模板,也就是“模板”,并不是实际存在的东西,而只是为了让我们更方便地生产某些东西的模具。C++的模板分为了两类,类模板与函数模板。分别用于让我们方便地“生产各种各样的函数与类”,它们都使用了template,class,typename几个关键字。为什么说是各种各样,看完了博客自然就明白了。下面介绍函数模板。

示例

template < class type>
type max(type fir,type sec)
{return fir > sec ? fir : sec;
}

template告诉编译器这是一个模板,紧跟在后面的<>中声明了模板形参,这些形参在模板中可以充当类型,声明可以选用class或者typename,暂时认为两者在C++中作用相同。普通函数的形参为一个变量,模板形参为一种变量类型。也就是,我们可以通过指定模板形参的类型。来个简单的例子。
比如int,float来形成不同的重载函数

template < class type...>
type max(type fir,type sec...)
{return fir > sec ? fir : sec;
}
void main()
{int a(1),b(2);float c(1),d(2);max(a,b);    //具现化int max(int fir,int sec);max(c,d);    //具现化int max(float fir,float sec);
}

第一个max使用了int类型的参数,相当于告诉函数模板,type对应于int,在具现化的函数模板中,type的作用相当于int。所以具现化的函数相当于int
max(int fir,int sec);相对应地,使用了float调用函数模板,也就是制定了type为float,与前一个函数形成了重载。

注:虽然float能够隐私转换为int,但是还是会具现化新的函数。只有当前的参数类型与已经具现化的函数模板完全匹配的时候,才会继续使用已经具现化的函数。

拓展

template < class type_1,class type_2...>
type_1 func(type_2 fir,type_1 sec,int thir)
{//return...
}

相对于前一个模板函数,这个模板函数的模板形参数量增加了,在普通的形参列表中,模板形参的顺序打乱了,还增加了int的形参。

  1. 在模板形参中,我们可以随意地定义任意数量的模板形参,但必须保证能够全部初始化。
  2. 使用了不同的类型名type_1,type_2...意味着我们可以指定多种类型的模板形参,其类型也可以不相同。
  3. 模板形参没有要求必须与普通函数形参一一对应,即在形参中的顺序可以随意打乱,其类型由相应的普通形参的类型决定。如,type_1的类型由sec的类型决定。
  4. 在模板函数中,除了模板形参外,可以使用内置的或者自定义的类型。

还是来个简单的例子

template < class type_1,class type_2>
void max(type_2 fir,type_1 sec,int)//最后的参数没有使用,可以直接忽略形参名
{std::cout<<fir<<"+"<<sec<<endl;
}
void main()
{int a(1);float b(1.0);max(a,b,1);                //1. 具现化void max(int fir,float sec,int);
}

第一个实参为int型,其对应的形参是type_2,所以type_2具现化后就是int。

第二个实参为float,其对应的形参type_1,所以type_1具现化后就是float。最后的具现化的函数就是int max(int fir,float sec,int);

指定参数类型

还记得使用STL容器的方法吗,比如定义一个vector类型的容器。STL也叫作标准模板库,也就是其内部也是通过模板实现的,所以这种名称后加类型名的方法对我们也同样适用。

void Select(int a)
{std::cout<<"是int型"<<endl;
}
void Select(float a)
{std::cout<<"是float型"<<endl;
}
template < class type_1,class type_2>
void myPrint(type_1 fir,type_2 sec)
{Select(fir);
}
void main()
{myPrint(1.0,1);            //输出"是float型"myPrint<int>(1.0,1);       //输出"是int型"
}

在上面的例子中,我们可以发现:

  1. 在调用模板函数的时候,我们可以通过直接指定模板形参的类型从而阻止普通函数形参对于模板形参的影响。但是,指定的类型与普通函数形参必须能够进行类型转换。

比如,内置类型的int与double可以相互转换,所以myPrint< double>(1)可用。但是string与int之间不可相互转换myPrint< string>(1)就没办法通过编译。假如我们定义了class My,其构造函数为public:My(int),那么认为My与int可以相互转换(本质上是隐式调用了My的构造函数),myPrint< My>(1)就可以通过编译。

类模板

假如你对函数模板还不会使用,请自行回顾,一些函数模板讲过的在下面不再赘述。

实例

template < class type_1,class type_2>
class Student
{
public:Student(){}Student(type_1 fir,type_2 sec){}Student(type_1 fir){}
private:type_1 value_1;type_2 value_2;...
};
void main()
{Student stu(1,1);               //errorStudent<int,float> stu(1,1);    //OK
}

template,class的作用与函数模板一致。不同的是:

  1. 类模板必须在使用的时候指定好模板形参的类型,编译器不会通过public接口,包括构造函数去作为模板形参类型的辨别依据。记得vector vec吧,没见过vector vec(1)吧。
  2. 使用类模板的时候,使用到的成员函数在主调语句必须可见。比如,上述的Student(type_1 fir,type_2 sec)在main中调用,其函数定义在main所在文件必须可见。再比如上述例子,假如其实现分配到如下几个文件,在链接的时候将出错。读者可以先记得,在“精通篇”会详细阐述这一点。
  3. 类模板中,慎用模板形参重载函数。上述的例子中,假如再增加Student(type_2)就会编译出错。编译器无法在Student(type_1)与Student(type_2)中做抉择。
//1.h
template < class type_1,class type_2>
class Student
{
public:...Student()    //有具体实现的构造函数{...}Student(type_1 fir,type_2 sec);
private:...
};
//1.cpp
#include"1.h"
Student< class type_1,class type_2>::Student()
{}
//core.cpp
#include"1.h"
void main()
{Student<int,int> stu(1,1);    //构造函数定义在1.cpp中,不可见,出错Student<int,int> stu();       //默认构造函数随1.hinclude,可见,编译通过
}

C++中模板的基本使用方法如上。下一篇博客将带大家进入模板特化以及深入解释上述例子无法编译的原因。

转载于:https://www.cnblogs.com/suimeng/p/4905607.html

C++模板详解——使用篇相关推荐

  1. html 自定义打印模板,HTML+CSS入门 自定义模板详解

    本篇教程介绍了HTML+CSS入门 自定义模板详解,希望阅读本篇文章以后大家有所收获,帮助大家HTML+CSS入门.< 首先总的stylecss和大模板都是当初angel_Kitty学姐的,嗯, ...

  2. IIS负载均衡-Application Request Route详解第一篇: ARR介绍

    IIS负载均衡-Application Request Route详解第一篇: ARR介绍   说到负载均衡,相信大家已经不再陌生了,本系列主要介绍在IIS中可以采用的负载均衡的软件:微软的Appli ...

  3. 26.C++- 泛型编程之类模板(详解)

    在上章25.C++- 泛型编程之函数模板(详解) 学习了后,本章继续来学习类模板   类模板介绍 和函数模板一样,将泛型思想应用于类. 编译器对类模板处理方式和函数模板相同,都是进行2次编译 类模板通 ...

  4. IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm

    自从本系列发布之后,收到了很多的朋友的回复!非常感谢,同时很多朋友问到了一些问题,有些问题是一些比较基本的问题,由于时间的缘故,不会一一的为大家回复,如果有不明白的,希望大家勤自学!本系列虽然不难,但 ...

  5. IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm(转载)

    IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm 自从本系列发布之后,收到了很多的朋友的回复!非常感谢,同时很多朋友问到了一些问题,有些问 ...

  6. 25.C++- 泛型编程之函数模板(详解)

    本章学习: 1)初探函数模板 2)深入理解函数模板 3)多参函数模板 4)重载函数模板 当我们想写个Swap()交换函数时,通常这样写: void Swap(int& a, int& ...

  7. Linux使用详解(进阶篇)

    文章目录 Linux使用详解(进阶篇) 1.Linux目录说明 2.操作防火墙 3.ulimit命令和history命令 4.RPM和Yum的使用 5.设置系统字符集 6.vi & vim编辑 ...

  8. Openharmony应用NAPI详解--基础篇

    NAPI是什么? 简单点理解就是在Openharmony里,实现上层js或ets应用与底层C/C++之间交互的框架. Openharmony里的官方解释:NAPI(Native API)组件是一套对外 ...

  9. Openharmony应用NAPI详解--进阶篇1

    NAPI面向C++的异步接口 3.C++实现NAPI异步接口需要做到三步 同步返回结果给js/ets调用者 另起线程完成异步操作 通过回调(callback)或Promise将异步操作结果返回 4.异 ...

最新文章

  1. 专访丨周志华:深度学习理论探讨比应用滞后太多
  2. 迁移学习——入门笔记
  3. opengl基础学习专题 (二) 点直线和多边形
  4. oracle 按日输出 取整数,Oracle按日周月分組統計,及next_day()函數詳解
  5. 面试题整理 1:将一个字符串转换为整数
  6. FatFsVersion0.01源码分析
  7. HH SaaS电商系统的销售订单毛利润模块设计
  8. javaScript的Math和Date对象
  9. Oracle 11g R1(11.1) Joins表连接
  10. 12. vim 编辑器
  11. matlab设计低通滤波器
  12. ATP-EMTP谁懂啊,急!!
  13. js简单实现切换图片上一张下一张功能
  14. windows常用系统命令
  15. 威廉.大内的Z理论(1981)--轉載
  16. 回溯算法--LeetCode-78 子集、LeetCode-90 子集Ⅱ
  17. php的表达爱意的一句代码,含蓄表达爱意的爱情诗句(70条)
  18. 计算机打字训练教学教案,打字机教案
  19. matlab2017硬件加速,现场影像增强中的硬件加速机制研究
  20. Libc堆管理机制及漏洞利用技术(一)

热门文章

  1. java如何学习javaweb学习课程
  2. Unity3D笔记 愤怒的小鸟六 弹弓发射小鸟
  3. thinkphp隐藏后台地址
  4. 基于ANN的6种调制信号自动调制识别(2ASK、4ASK、2FSK、4FSK、2PSK、4PSK)
  5. 使用datatables 中文排序
  6. 算法与数据结构题目的 PHP 实现:栈和队列 由两个栈组成的队列
  7. 推荐五星级C语言学习网站
  8. 【线性规划和网络流24题】
  9. MySql——安装与配置与启动和停止
  10. 下面代码打印的结果?