C++ 模板初阶【函数模板,类模板】

文章目录

  • 泛型编程
  • 函数模板
    • 概念
    • 函数模板的格式
    • 函数模板的原理
    • 函数模板的实例化
      • 隐式实例化:让编译器根据实参推演模板参数的实际类型
      • 显式实例化:在函数名后的<>中指定模板参数的实际类型
    • 函数模板的匹配规则
  • 类模板
    • 概念
    • 类模板格式
    • 类模板的实例化

泛型编程

在我们敲代码的时候,我们一般都是怎样实现的一个交换函数的的?
例如:

void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}.........

但是使用函数重载要交换的类型少还好,倘若类型多的话会让程序变得冗杂,那么C++ 在这个问题上就有了模板这一概念
就好比:
在这里插入图片描述C++提供了这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。感谢前人早已将树栽好,我们只需在此乘凉嘿嘿。
编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

模板被分为 函数模板 和 类模板 两种

函数模板

概念

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

函数模板的格式

函数模板允许我们为不同的数据类型创建一个函数形式,它使用一个代表类型的"占位符"(通常称为模板参数)。当编译器遇到对该模板函数的具体调用时,它会根据传入的实际数据类型来实例化一个相应的函数。

template<typename T1, typename T2,…,typename Tn>
返回值类型 函数名(参数列表){}

就用刚才交换函数举例子:

template <typename T>
void Sweap(T& n1, T& n2)
{T temp = n1;n1 = n2;n2 = temp;
}

其中T就是我们之前打比方的占位符(模板参数),而编译器会根据你传过来的数值判断进而实现不需要数据类型的通用模板
注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)

函数模板的原理

那么我们的祖师爷是怎么样实现的函数模板来让我们“偷懒”的呢?

其实:
函数模板的原理是基于C++编译器的模板实例化能力。函数模板允许你定义一个蓝本,但是这个蓝本并不是函数是编译器用使用方式产生特定具体类型函数的模具,编译器则利用这个蓝本为不同类型生成具体的函数实例。这个过程叫做模板实例化。所以就是通过编译器减少我们的工作量。
在这里插入图片描述
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。
所以例如:

template <typename T>
void Sweap(T& n1, T& n2)
{T temp = n1;n1 = n2;n2 = temp;
}

typename T 告诉编译器,T 是一个待定的类型,swap 函数可以用任何类型的 ab 来实例化。当你调用 swap(x, y),并且 xyint 类型时,编译器自动生成一个处理 int 类型的 swap 函数版本。如果 xydouble 类型,则生成一个处理 double 类型的版本

函数模板的实例化

不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化显式实例化

隐式实例化:让编译器根据实参推演模板参数的实际类型

template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 20;double b1 = 10.1, b2 = 20.2;cout << Add(a1, a2) << endl;cout << Add(b1, b2) << endl;return 0}

在这里有一个细节:
在这里插入图片描述
该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
通过实参a1将T推演为int,通过实参b1将T推演为double类型,但模板参数列表中只有一个T,
编译器无法确定此处到底该将T确定为int 或者 double类型而报错
注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅 Add(a1, b1);

此时有两种处理方式:

  1. 用户自己来强制转化
	cout << Add(a1, (int)b2) << endl;//或者cout << Add((double)a1, b2) << endl;
  1. 使用显式实例化

显式实例化:在函数名后的<>中指定模板参数的实际类型

int main(void)
{int a = 10;double b = 20.0;// 显式实例化Add<int>(a, b);return 0;
}

如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

函数模板的匹配规则

  1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
// 专门处理int的加法函数
int Add(int left, int right)
{return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{return left + right;
}
void Test()
{Add(1, 2); // 与非模板函数匹配,编译器不需要特化Add<int>(1, 2); // 调用编译器特化的Add版本
}
  1. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
// 专门处理int的加法函数
int Add(int left, int right)
{return left + right;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{return left + right;
}
void Test()
{Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}
  1. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

类模板

概念

有了函数模板的铺垫,类模板我们理解起来也顺理成章。类模板允许在定义类的时候使用一个或多个占位符表示成员变量或成员函数中的某些类型。类模板非常适合用来创建如容器(如数组、链表等)等数据结构。

类模板格式

template<class T1, class T2, …, class Tn>
class 类模板名
{
// 类内成员定义
};

示例:

// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{ 
public :Vector(size_t capacity = 10): _pData(new T[capacity]), _size(0), _capacity(capacity){}// 使用析构函数演示:在类中声明,在类外定义。~Vector();void PushBack(const T& data)void PopBack()// ...size_t Size() {return _size;}T& operator[](size_t pos){assert(pos < _size);return _pData[pos];}private:T* _pData;size_t _size;size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{if(_pData)delete[] _pData;_size = _capacity = 0;
}

类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

// Vector类名,Vector<int>才是类型
Vector<int> s1;
Vector<double> s2;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/458475.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PCIE和USB 耦合电容放置位置记录- 一般放置在TX端

PCIE耦合电容位置 以下为引用内容&#xff0c;为记录而做的本篇文章&#xff1a; 1、PCIe标准里面明确规定&#xff1a;当两个设备通过连接器互联时&#xff0c;必须放置交流耦合电容到TX端&#xff1b; 2、放远放近最大的不同时高速信号传输中的介质损耗和趋肤效应不同&#…

MySQL:从基础到实践(简单操作实例)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 下载前言一、MySQL是什么&#xff1f;二、使用步骤1.引入库2.读入数据 提交事务查询数据获取查询结果总结 下载 点击下载提取码888999 前言 在现代信息技术的世界…

电力负荷预测 | 基于LSTM、TCN的电力负荷预测(Python)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 电力负荷预测 | 基于LSTM、TCN的电力负荷预测(Python) 源码设计 #------------------

相机图像质量研究(5)常见问题总结:光学结构对成像的影响--景深

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

springboot项目启动报错:dynamic-datasource can not find primary datasource

项目启动报错信息 Caused by: com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException: dynamic-datasource can not find primary datasourceat com.baomidou.dynamic.datasource.DynamicRoutingDataSource.determinePrimaryDataSource(DynamicRoutingDat…

国产信创领跑者:暴雨信息的创新与实践

随着数字化转型的加速推进&#xff0c;信创产业作为数字经济发展的重要支柱&#xff0c;正日益受到社会各界的广泛关注。在这个大背景下&#xff0c;暴雨信息积极响应国家号召&#xff0c;全面适配国产化&#xff0c;推动信创产业的技术创新和应用拓展&#xff0c;成为了行业的…

springboot基础案例(二)

文章目录 前言一.需求分析: 分析这个项目含有哪些功能模块二.库表设计(概要设计): 1.分析系统有哪些表 2.分析表与表关系 3.确定表中字段(显性字段 隐性字段(业务字段))2.1 创建一个库: ems-thymeleaf2.2 创建 2张表三.编码(环境搭建)1.创建一个springboot项目 项目名字: ems-t…

如何将SD卡众多文件打包成一个.img文件方便Windows的Windisk32工具一键烧写?

相信不少SOC FPGA用户在第一次设计SD卡image时都参考过Intel的经典教程 EmbeddedLinuxBeginnerSGuide &#xff0c;教程里面演示制作SD卡image时&#xff0c; 需要将SD卡手动分成3分区&#xff08;fat32、raw 和ext3&#xff09;&#xff0c;然后将preloader 、uboot、kernel、…

vue教程-介绍与使用

vue介绍 介绍 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。 安装 最简单的例子就是&#xff0c;创建一个htm…

Android CMakeLists.txt语法详解

一.CMake简介 你或许听过好几种 Make 工具&#xff0c;例如 GNU Make &#xff0c;QT 的 qmake &#xff0c;微软的 MSnmake&#xff0c;BSD Make&#xff08;pmake&#xff09;&#xff0c;Makepp&#xff0c;等等。这些 Make 工具遵循着不同的规范和标准&#xff0c;所执行的…

相机图像质量研究(4)常见问题总结:光学结构对成像的影响--焦距

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

【AG32VF407】国产MCU+FPGA,更新官方固件解决8Mhz内部晶振不准,Verilog实测7.9Mhz!

视频讲解 [AG32VF407]国产MCUFPGA&#xff0c;更新官方固件解决8Mhz内部晶振不准&#xff0c;Verilog实测7.9Mhz&#xff01; 实验过程 之前出现的双路pll不同频率的测试中&#xff0c;提出了内部晶振输出不准的问题&#xff0c;和官方沟通后得到极大改善&#xff0c;方法如下…