当前位置: 首页 > news >正文

模板初阶(详解)

一、泛型编程

为了引出模板,我们来看下面代码,比如要实现不同类型的交换函数,如下:

void Swap(int& a, int& b)
{int c = a;a = b;b = c;
}
void Swap(char& a, char& b)
{char c = a;a = b;b = c;
}
void Swap(double& a, double& b)
{double c = a;a = b;b = c;
}

        这样每个类型交换都需要写一个函数重载,其中代码的重复率很高,只有类型不同而逻辑都一样,写起来也非常的繁琐,那我们能不能写一个通用的函数告诉编译器一个模版让编译器根据不同的类型利用该模版来生成代码呢?这就是本章的主题——模板。

泛型编程编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

模板分为函数模板和类模板,接下来我们分别来详细学习。

二、函数模版

函数模板的格式:

template<typename T1, typename T2 , ... ... ,typename Tn>

返回类型 函数名(参数列表){}

注意:这里typename可以换为calss,但不能换位struct。

代码示例:

template<typename T>
void Swap(T& a, T& b)
{T c = a;a = b;b = c;
}

        这样我们写一个模板就可以省了很多代码,还增加可读性。以上并不是一个函数只是一个模板,需要等到使用这个函数的时候编译器会具体的实例化出对应类型的函数,它和写多个函数重载并没有本质区别,只是说这个工作让编译器帮我们做了而已,在效率上并没有提升。

        需要注意的是如果在这里传两个不同的参数的话会编译报错,因为这里模板参数只有一个,而传入两个不同的类型的实参的时候,编译器并不会帮你强制类型转换,因为它并不知道转成那个类型出了问题它可不背锅。那么我们硬要传两个不同的参数的话,可以显示的强制类型转换成两个相同类型,或者调用的时候在函数名后面加<>,尖括号里面加类型名,也就是显示实例化

如下示例:

        这里有人可能会试图去测试Swap模板,结构还是编不过,这是因为不符合引用的语法,我在之前讲过,如下链接:

C++入门基础-CSDN博客

        对于这种情况,我们可以在外面进行强制类型转换存入新的变量里面然后再把新的变量代替原来变量做函数参数。 

        函数模板与模板函数的区别:通过这两个词就可以看出来函数模板的主语是模板,模板函数的主语是函数,那么接下来就好理解了,函数模板就是一个模板如刚才我们写的那些都是函数模板,而模板函数是函数模板经过实例化后生成的函数。

三、类模板

类模板的定义个格式:

template<typename T1, typename T2, ... ... ,typename Tn>

class 类模板名

{}

同样这里typename可以换为calss,但不能换位struct。

        对于类模板与函数模板不同,类模板在使用的时候必须显示实例化,在类模板名后面加<>尖括号里面放入类型名。

注意:类模板不是类,要经过实例化后才是类。如下一个Stack类模板的部分:

// 类模版
template<typename T>
class Stack
{
public :Stack(size_t capacity = 4){_array = new T[capacity];_capacity = capacity;_size = 0;} void Push(const T& data);//... ...
private:T* _array;size_t _capacity;size_t _size;
};
// 模版不建议声明和定义分离到两个文件.h 和.cpp会出现链接错误
template<class T>
void Stack<T>::Push(const T& data)
{// 扩容//... ..._array[_size] = data;++_size;
} 
int main()
{Stack<int> st1;Stack<double> st2;return 0;
}

四、模板参数的匹配原则

接下来讲的匹配原则对于类模板和函数模板都是相同的,我们就以函数模板为例。

一个非模板函数是可以和模板函数同名的,而怎么区分编译器会调用那个呢,如下:

template<typename T>
T Add(T a, T b)
{return a + b;
}
int Add(int a, int b)
{return a + b;
}
int main()
{int a1 = 2, b1 = 4;double a2 = 2.5, b2 = 1.5;int ret1=Add(a1, b1);double ret2=Add(a2, b2);return 0;
}

        编译器在做调用(不仅指函数的调用)的时候有一个特点,有现成的就调现成的,没现成的就调用模板实例化一个。如这里第一个Add调用的是非模板函数,第二个Add调用的是模板函数。 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Linux驱动.之I2C,iic驱动层(二)
  • 字体识别验证码的介绍!
  • 【论文阅读笔记】ZooKeeper: Wait-free coordination for Internet-scale systems
  • 机器学习用python还是R,哪个更好?
  • 预防碰撞安全系统,让叉车不再盲动!
  • 编程-设计模式 27:组合实体模式
  • MySQL面试题全解析:准备面试所需的关键知识点和实战经验
  • 恒创科技:IPv4 和 IPv6 之间的主要区别
  • 编程式路由编程
  • 【学习笔记】用线段树维护区间计数问题
  • PostgreSQL学习笔记(下)
  • Python学习笔记(四)
  • 从概念到落地:全面解析DApp项目开发的核心要素与未来趋势
  • thinkphp 5.0.24生成模块
  • shortcut下载慢试试这个
  • 2017年终总结、随想
  • Apache Zeppelin在Apache Trafodion上的可视化
  • magento2项目上线注意事项
  • Node + FFmpeg 实现Canvas动画导出视频
  • Promise初体验
  • React-redux的原理以及使用
  • Solarized Scheme
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • TypeScript实现数据结构(一)栈,队列,链表
  • Vue组件定义
  • 包装类对象
  • 搭建gitbook 和 访问权限认证
  • 人脸识别最新开发经验demo
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 微信小程序开发问题汇总
  • 湖北分布式智能数据采集方法有哪些?
  • ​iOS安全加固方法及实现
  • ​油烟净化器电源安全,保障健康餐饮生活
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • (07)Hive——窗口函数详解
  • (1)(1.9) MSP (version 4.2)
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (C++17) std算法之执行策略 execution
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (三)docker:Dockerfile构建容器运行jar包
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (转)IOS中获取各种文件的目录路径的方法
  • ******之网络***——物理***
  • .describe() python_Python-Win32com-Excel
  • .net 7和core版 SignalR
  • .NET Core中如何集成RabbitMQ
  • .NET delegate 委托 、 Event 事件,接口回调
  • .net 设置默认首页
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .NET大文件上传知识整理