C语言无法实现的泛型编程,C++是如何实现的?模板

news2025/2/27 11:14:33

1.泛型编程

如何实现一个通用的交换函数?

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;
}
void Swap(char& left, char& right)
{
	char temp = left;
	left = right;
	right = temp;
}
……

C++中允许使用函数重载,对于不同的类型需要调用不同的Swap函数,这样的话就会很麻烦,只要有新类型的出现,就需要增加对应的函数;而且这种代码的可维护性很低,一个地方出错的话所有的重载都会出错。

那能不能我们不写Swap函数交换的类型,让编译器根据不同的类型利用没有给出类型的Swap函数进行交换呢?

C++中能够存在这样一个模具,通过向这个模具中填充不同材料(类型),来获得不同材料的铸件(生成具体类型的代码)。

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

模板可以分为:函数模板和类模板。

2.函数模板

2.1 函数模板的概念

函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其类型

2.2 函数模板的格式

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

举个栗子:

template<typename T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

 注意:class是用来定义模板参数的关键字,也可以使用typename,我平常的话用class比较多;但是切记不能使用struct代替class

2.3 函数模板的原理

template <class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 10, b = 20;
	Swap(a, b);
	double d1 = 1.1, d2 = 2.2;
	Swap(d1, d2);
	char c1 = 'a', c2 = 'c';
	Swap(c1, c2);
	return 0;
}

在编译器编译阶段,对于函数模板的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。 

2.4 函数模板的实例化

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

2.4.1 隐式实例化 

让编译器根据实参推演模板参数的实际类型。

上面我们所写的就是一种隐式实例化:

int main()
{
	int a = 10, b = 20;
	Swap(a, b);

	double d1 = 1.1, d2 = 2.2;
	Swap(d1, d2);

	char c1 = 'a', c2 = 'c';
	Swap(c1, c2);
	return 0;
}

2.4.2 显式实例化 

template <class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
int main(void)
{
	int a = 10, b = 20;
	// 显式实例化
	Swap<int>(a, b);
	return 0;
}

2.5 模板参数的匹配规则

1.一个非模板函数可以和一个同名的模板函数同时存在,而且该函数模板还可以被实例化为这个非函数模板函数。

template <class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
void Swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 10, b = 20;
	Swap(a, b);      //与非函数模板匹配,编译器不需要特化
	Swap<int>(a, b); //调用编译器特化的函数
	return 0;
}

 2.对于非函数模板和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数而不会特化产生一个实例。如果模板可以产生一个更好匹配的函数,那么将选择模板。

// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
//函数模板
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}
int main()
{
	Add(1, 2);   // 与非函数模板类型完全匹配,不需要函数模板实例化
	Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
	return 0;
}

3.函数模板不允许自动类型转换,但普通函数可以进行自动类型转换。

template <class T>
void Swap(T& a, T& b)
{
	double tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 10, b = 20;
	Swap(a, b);
	return 0;
}

这段代码是无法通过编译的,因为函数模板中发生了类型转换。

如果是函数模板的话,就可以发生类型转换:

void Swap(int& a, int& b)
{
	double tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 10, b = 20;
	Swap(a, b);
	return 0;
}

普通函数是能够通过编译的,只是从int -> double会有数据丢失。

3.类模板

3.1 类模板的定义格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
	// 类内成员定义
};
template<class T>
class Vector
{
private:
	T* _pData;//动态开辟的内存空间
	int _size;
	int _capacity;
};

3.2 类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后面跟上<>,然后将实例化的类型放在<>中。

类模板名字不是真正的类,而实例化的结果才是真正的类。

Vector<int> v1;
Vector<double> v2;

C++模板部分的内容还有很多,正是因为模板的存在,C++实现了泛型编程;像非类型模板参数、函数模板化、类模板特化等内容在本篇文章中都没有涉及到,后面会继续更新,期待的话就点个关注吧,你们的支持是我前进的动力。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rt-thread 之------fal移植

rt-thread 之 fal移植 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录rt-thread 之 fal移植前言一、fal是什么&#xff1f;二、移植1.片内flash fal移植step1&#xff1a;使能RT-Thread Components--->中的fal选…

MySQL查询优化实例

| 导语 通过几个小实例&#xff0c;对实际会经常用到的查询进行对比&#xff0c;通过MySQL的执行计划分析语句的执行性能&#xff0c;最后分析几个在实际中会遇到的小问题。 我们知道一般应用系统的读写比列在10:1左右&#xff0c;而且插入操作和一般的更新操作很少出现性能问…

jenkins的安装与配置(超详细)

Jenkins官网&#xff1a;https://jenkins.io/ 或 https://www.jenkins.io/zh/download/Jenkins官网文档&#xff1a;https://www.jenkins.io/zh/doc/jenkins安装包&#xff1a;http://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat/清华镜像&#xff1a;http://updates.jenkins…

SpringMVC学习篇(六)

SpringMVC之全局异常的处理 1 注解方式 1.1 准备工作 1.1.1 导入springmvc依赖和lombok依赖 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.22</ve…

Nginx实现四层代理与七层代理

目录 一、实验环境准备 1、准备三台服务器 2、安装nginx环境 3、启动nginx环境 二、设置Nginx七层代理 1、proxy代理服务器配置&#xff08;轮询&#xff09; 2、设置加权轮询 3、健康检测功能 4、解决重复登录问题&#xff08;源地址哈希ip_hash&#xff09; 三、设…

StarRocks从入门到精通系列五:导入数据

StarRocks从入门到精通系列五:导入数据 一、导入总览二、从 Apache Kafka 持续导入三、使用 Apache Spark™ 批量导入四、从 Apache Flink持续导入一、导入总览 下图详细展示了在各种数据源场景下,应该选择哪一种导入方式。 数据导入是指将原始数据按照业务需求进行清洗、…

Springboot常用参数注解

访问路径为http://localhost:8080/ PathVariable GetMapping("/get/{id}/blank/{name}")public Map getValue(PathVariable("id") Integer id,PathVariable("name") String name,PathVariable Map<String,String> kv){Map map new Hash…

在Jeston NX上部署运行PaddleOCR教程(安装whl包方法)

文章目录基本概念介绍1.确定盒子环境pythonCUDAcuDNNTensorRT版本1.1 我还没有安装环境&#xff1a;一步到位整体安装1.2 我已经安装了环境&#xff1a;查询盒子环境版本1.3 默认python版本设置2.安装PaddlePaddle3. 安装PaddleOCR4. 运行例程5. 后续工作附&#xff1a;参考教程…

Java---Arrays类的常用方法

目录 1&#xff1a;Arrays常用的API方法 2&#xff1a;API方法具体举例 &#xff08;1&#xff09;toString方法 &#xff08;2&#xff09;sort方法 &#xff08;3&#xff09;binarySearch方法 &#xff08;4&#xff09;fill方法 &#xff08;5&#xff09;copyOf方法 …

如何在自己的项目中实现脚手架的命令行交互

背景 所在的公司大多数项目都是用Taro脚手架搭建的&#xff0c;因为业务上要实现多端开发 答应我&#xff0c;如果可以千万不要选择跨端开发&#x1f64f;。所以不同环境下运行、打包会有多个命令。如下图所示&#xff1a; 嗯&#xff1f;&#xff1f;好熟悉感觉在哪见过&…

LeetCode刷题(python版)——Topic69. x 的平方根

一、题设 给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。 由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。 注意&#xff1a;不允许使用任何内置指数函数和算符&#xff0c;例如 pow(x, 0.5) 或者 x ** 0.5 。 示例 1…

2022年下半年网络规划设计师下午真题及答案解析

1.若系统正在将( )文件修改的结果写回磁盘时系统发生掉电&#xff0c;则对系统的影响相对较大。A.目录 B.空闲块 C.用户程序 D.用户数据 2.采用三级模式结构的数据库系统中&#xff0c;如果对一个表创建聚簇索引&#xff0c;那么改变的是数据库的( )。 A.外模式…

信号(1.信号概念 2.信号的处理方式 3.信号阶段 用户态,内核态)

目录1.临界资源2.临界值3.原子性4.互斥5.什么是信号量6.什么是信号1.信号概念2.信号的处理方式3.信号阶段1.信号使用前&#xff0c;信号的产生2.为什么进程会崩溃3.信号产生中4.信号产生后1.临界资源 被多个进程能够看到看到额资源叫做临界资源 如果没有堆临界资源进任何的保护…

技术分享 | AlertManager 源码解析

作者&#xff1a;石蓓蓓 爱可生研发工程师&#xff0c;主要负责爱可生产品云DMP树产品的研发工作。 本文来源&#xff1a;原创投稿 *爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。 AlertManager 是处理对应用程序的告警的…

ZIP压缩文件的打开密码和自动加密有什么不同?

ZIP是常用的压缩文件格式&#xff0c;对于重要的内容&#xff0c;我们还可以设置密码&#xff0c;从而达到保护文件内容的目的。 通过WinRAR给ZIP文件设置密码保护&#xff0c;可以设置“打开密码”和“自动加密”&#xff0c;那两者有什么不同呢&#xff1f; 设置打开密码是…

【附源码】Python计算机毕业设计万达影院售票管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

图相似度计算——SIMGnn源码解读

在运行代码的时候&#xff0c;需要首先指定参数&#xff0c;--histogram&#xff0c;表示使用直方图特征 1.数据集 数据集我们使用的是AIDS数据集&#xff0c;为内置的数据集&#xff0c;整个数据集大约700张图&#xff0c;每个图少于10个点&#xff0c;每个点由29维的向量组成…

多视角碰撞,探索 Serverless 企业落地更多可能性丨阿里云用户组厦门站

2022 年 9 月 24 日&#xff0c;阿里云在厦门举办了第 12 场阿里云用户组&#xff08;AUG&#xff09;活动&#xff0c;活动主题为“提效降本&#xff0c;Serverless 助力企业快速落地云原生”&#xff0c;吸引了众多技术从业者及企业管理者到场交流。 2009 年&#xff0c;伯克…

油气田工业控制系统现状

石油石化行业综述 石油石化行业分为上游、中游和下游。其中&#xff0c;上游从事的业务包括原油、天然气 的勘探、开发&#xff0c;中游主要是油气 的存储与运输&#xff0c;下游则涵盖炼油、化工、天然气加工等流程型业务及加油站零售等产品配送、销售型业务。通常情况下&…

常用 numpy 函数(长期更新)

文章目录np.where()np.zeros()np.zeros_like()np.divide()np.linalg.norm()np.uint8()np.clip()np.where() np.where有两种用法 np.where(condition,x,y) 当where内有三个参数时&#xff0c;第一个参数表示条件&#xff0c;当条件成立时where方法返回x&#xff0c;当条件不成…