C++:模板(1)

news2024/12/23 17:15:06

目录

实现泛型的交换函数

函数模板

1.概念

2.格式

3.原理

4.函数模板实例化

5.函数模板参数的匹配原则

类模板

1.定义格式

2.实例化

3.声明与定义问题


实现泛型的交换函数

我们实现一个对所有类型都通用的交换函数,可以用函数重载来实现。

void Swap(int& x, int& y)
{
	int temp = x;
	x = y;
	y = temp;
}
void Swap(double& x, double& y)
{
	double temp = x;
	x = y;
	y = temp;
}
void Swap(char& x, char& y)
{
	char temp = x;
	x = y;
	y = temp;
}

//......

使用函数重载可以实现,但有几个缺点:

1.重载函数仅仅是类型不同,代码复用率低,当有新类型出现的时候,就又需要增加对应的函数。

2.代码的可维护性低,一个出错就可能导致所有的重载出错。

那我们能不能自己实现一个交换函数的模具,我们传递不同类型的值,就根据这个类型生成对应的交换函数?

就如同下面的浇筑过程。

答案是可以的,这就是C++中的模板模板分为函数模板和类模板,模板又是泛型编程的基础。

泛型编程:编写与类型无关的通用代码,实现代码复用。

函数模板

1.概念

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

2.格式

模板都需要用一个关键字template,使用格式如下:

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

​

typename是用来定义模板参数的关键字,也可以使用class,但是不能用struct代替。

用模板实现交换函数

template<class T>
void Swap(T& x, T& y)
{
	T temp = x;
	x = y;
	y = temp;
}

具体例子

template<class T>
void Swap(T& x, T& y)
{
	T temp = x;
	x = y;
	y = temp;
}


int main()
{
	int i1 = 10;
	int i2 = 50;
	cout << "交换前i1、i2为:" << i1 << " " << i2 << endl;
	Swap(i1, i2);
	cout << "交换后i1、i2为:" << i1 << " " << i2 << endl;
	cout << endl;

	double d1 = 28.8;
	double d2 = 67.6;
	cout << "交换前d1、d2为:" << d1 << " " << d2 << endl;
	Swap(d1, d2);
	cout << "交换后d1、d2为:" << d1 << " " << d2 << endl;
	cout << endl;

	char ch1 = 'c';
	char ch2 = 'x';
	cout << "交换前ch1、ch2为:" << ch1 << " " << ch2 << endl;
	Swap(ch1, ch2);
	cout << "交换后ch1、ch2为:" << ch1 << " " << ch2 << endl;
	cout << endl;
	return 0;
}

 

3.原理

函数模板是一个蓝图,他本身并不是函数,是编译器产生特定具体类型函数的模具。

模板就是将本来我们做的重复的事情交给了编译器。

在编译器编译阶段,对于函数模板的使用,编译器根据传入的实参类型来生成对应类型的函数以供调用。比如:当double模板使用函数模板时,编译器通过实参的类型确定T为double,然后生成一个double类型的函数,对于其他类型也是如此。

4.函数模板实例化

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

实例化出来的函数就是模板函数,模板函数的生成就是将函数模板的类型形参实例化的过程。

1.隐式实例化:编译器根据传入实参推算模板参数的实际类型

template<class T>
T Add(const T& x, const T& y)
{
	return x + y;
}

int main()
{
	int i1 = 20, i2 = 30;
	cout << "i1 + i2 =" << Add(i1, i2) << endl;
	cout << endl;

	double d1 = 15.0, d2 = 20.0;
	cout << "d1 + d2 =" << Add(d1, d2) << endl;
	cout << endl;
	return 0;
}

注意以下这种方式时不能通过编译的:

Add(i1, d1);

因为在编译阶段,编译器已经根据i1的类型推断T为int类型,而模板参数列表T只有一个,当编译器接收到d1时,发现时double类型,那编译器就会因为无法确定将T确定为int还是double而报错

在模板中,编译器一般不会进行类型转换操作,如果转换出问题,那编译器就需要背黑锅。

这种报错有两种解决方式:1.我们自己强制转化 2. 显式实例化

//用户自己强制转化
Add(i1, (int)d1);

//显式实例化
Add<int> (i1, d1);

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

int main()
{
	int i1 = 10;
	double d1 = 10.0;

	//显式实例化
	Add<int>(i1, d1);

	return 0;
}

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

5.函数模板参数的匹配原则

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

// 专门处理int的加法函数
int Add(int x, int y)
{
	return x + y;
}
// 通用加法函数
template<class T>
T Add(T x, T y)
{
	return x + y;
}
void Test()
{
	Add(1, 2); // 与非模板函数匹配,编译器不需要生成对应类型的模板函数
	Add<int>(1, 2); // 调用编译器特化的Add版本
}

2.对于非模板函数与同名的函数模板,在条件相同的情况下,在调用时会优先调用非模板函数而不会使用函数模板产生实例。如果函数模板可以实例化产生更加匹配的模板函数,那么会选择模板函数。

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

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

类模板

1.定义格式

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

例子

// 类模版
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; // int
	Stack<double> st2; // double
	return 0;
}

2.实例化

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

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

// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double

3.声明与定义问题

为什么在c++中,模板(函数)的声明和定义不建议分离到两个文件?

 

func.h 函数声明

func.cpp 函数定义

test.cpp 调用函数

报链接错误的直接原因就是链接时,符号表没有对应函数的地址。

1.代码开始编译的时候,首先就预处理,把头文件展开、宏替换、条件编译、去掉注释,.h和对应对的.cpp文件合在一起生成.i文件

2.然后就到编译,根据语法树,检查语法,生成对应对的汇编代码,模板这时候问题就出在这,函数的.i文件,有声明有定义,没有具体类型,test.i中有函数的声明,有类型,但是没有定义,所以就不能生成具体的函数符号表也就没有对应的地址,函数.i文件普通函数有声明有定义有类型,可以生成,这时test.i还是转换成汇编 call func(?),等着链接时把地址连接上,也没有报错,由.i文件生成.s文件;

3.编译完就到了汇编,汇编代码转换成二进制机械码,生成.obj文件;

4.链接时把目标文件合并在一起生成可执行程序,并把需要的函数地址等连接上。

解决方案:声明定义不分离;显式实例化模板。


拜拜,下期再见😏

摸鱼ing😴✨🎞

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

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

相关文章

Map和Set,TreeMap和TreeSet,HashMap和HashSet

文章目录 TreeSet和TreeMap二叉搜索树模拟TreeMAp定义 基本操作插入查找删除(难点)遍历性能分析应用场景 Map&&Set模型 HashMap常用方法 HashSet常用方法HashMap和HashSet区别数据结构不同元素类型不同方法不同使用场景不同 TreeSet和TreeMap 定义&#xff1a; TreeSe…

个人健康档案管理系统

基于springbootvue实现的个人健康档案管理系统&#xff08;源码L文ppt&#xff09;4-076 4.1 系统功能结构设计 根据对个人健康档案管理系统的具体需求分析&#xff0c;把系统可以划分为几个不同的功能模块&#xff1a;管理员可以对系统首页、用户管理、健康体检管理、疫…

智能密码、指纹锁语音芯片ic方案 可存放40s语音内容 NVD语音芯片

随着科技的飞速发展&#xff0c;智能家居安全领域迎来了前所未有的变革。智能密码与指纹锁作为现代家庭安全防护的重要一环&#xff0c;其背后的语音芯片IC开发更是这一变革中的关键技术突破。 智能密码、指纹锁语音芯片ic方案 选型与简介&#xff1a; NVD语音芯片是一款低成…

基于JAVA+SpringBoot+Vue的疫苗发布和接种预约系统

基于JAVASpringBootVue的疫苗发布和接种预约系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f3…

AlmaLinux 安裝JDK8

在 AlmaLinux 上安装 JDK 8 可以通过包管理器 dnf 来完成。AlmaLinux 是基于 RHEL 的一个开源发行版&#xff0c;因此其包管理系统和 RHEL 类似。以下是详细的步骤来安装 OpenJDK 8 1. 更新系统包列表 sudo dnf update -y 2. 安装 OpenJDK 8 使用 dnf 安装 OpenJDK 8。你可…

【Python-tkinter】实现简单的文本编辑器(附带教程源码)

如果你也是刚入门的小伙伴呢&#xff0c;小编为你们准备了入门Python学习籽料和Python入门实践&#xff0c;点击领取&#xff08;无偿获得&#xff09; 利用tkinter实现简单的文本编辑器。创建一个简单的文本编辑器。可以用读文件的方式在一个文本域里显示一些文字供用户编辑…

大模型分布式训练并行技术(七)-自动并行

近年来&#xff0c;随着Transformer、MOE架构的提出&#xff0c;使得深度学习模型轻松突破上万亿规模参数&#xff0c;传统的单机单卡模式已经无法满足超大模型进行训练的要求。因此&#xff0c;我们需要基于单机多卡、甚至是多机多卡进行分布式大模型的训练。 而利用AI集群&a…

5--苍穹外卖-SpringBoot项目中菜品管理 详解(一)

目录 公共字段自动填充 问题分析 实现思路 代码开发 步骤一 步骤二 功能测试 新增菜品 需求分析和设计 代码开发 文件上传接口 功能测试 1--苍穹外卖-SpringBoot项目介绍及环境搭建 详解-CSDN博客 2--苍穹外卖-SpringBoot项目中员工管理 详解&#xff08;一&#…

医疗器械库存管理软件 符合gsp要求

软件介绍&#xff1a; 盘谷医疗器械进销存管理软件契合医疗器械行业特点&#xff0c;符合gsp要求&#xff0c;专为一二三类医疗器械经营企业开发的医疗器械进销存、质量验收、GSP管理、UDI扫码识别、财务管理一体化经营管理系统&#xff0c;符合药监新版医疗器械经营质量管理规…

C++在线开发环境搭建(WEBIDE)

C在线开发环境搭建 一、环境说明1.1 系统基础环境说明1.1 docker-ce社区版安装 二、codeserver构建2.1 构建codeserver环境的docker容器2.2 构建docker镜像2.3 运行docker2.4 运行展示 三、构建codeserver中的c开发环境3.1 插件下载3.2 插件安装 四、其他知识4.2 code-server配…

vue仿chatGpt的AI聊天功能--大模型通义千问(阿里云)

vue仿chatGpt的AI聊天功能–大模型通义千问&#xff08;阿里云&#xff09; 通义千问是由阿里云自主研发的大语言模型&#xff0c;用于理解和分析用户输入的自然语言。 1. 创建API-KEY并配置环境变量 打开通义千问网站进行登录&#xff0c;登陆之后创建api-key&#xff0c;右…

20个数字经济创新发展试验区建设案例【2024年发布】

数据简介&#xff1a;国家数字经济创新发展试验区的建设是一项重要的国家战略&#xff0c;旨在推动数字经济与实体经济的深度融合&#xff0c;促进经济高质量发展。自2019年10月启动以来&#xff0c;包括河北省&#xff08;雄安新区&#xff09;、浙江省、福建省、广东省、重庆…

【java】前端RSA加密后端解密

目录 1. 说明2. 前端示例3. 后端示例3.1 pom依赖3.2 后端结构图3.3 DecryptHttpInputMessage3.4 ApiCryptoProperties3.5 TestController3.6 ApiCryptoUtil3.7 ApiDecryptParamResolver3.8 ApiDecryptRequestBodyAdvice3.9 ApiDecryptRsa3.10 ApiCryptoProperties3.11 KeyPair3…

一天面了8个Java后端,他们竟然还在背5年前的八股文!

今天面了8个Java候选人&#xff0c;在面试中我发现他们还停留在面试背八股文的阶段&#xff0c;5年前面试背八股文没问题&#xff0c;随着市场竞争越来越激烈&#xff0c;再问普通的Java八股文已经没有意义了&#xff0c;因为考察不出来获选人的真实实力&#xff01; 现在面试…

VIGOSERVO帝人伺服驱动器维修ARN135-F ARS135-25

帝人VIGOSERVO驱动器维修TEIJIN SEIKI伺服驱动器全系列型号修理。 关于VIGOSERVO伺服驱动器维修的相关内容&#xff0c;可以归纳为以下几个方面&#xff1a; 一、维修概述 VIGOSERVO伺服驱动器作为自动化设备组件&#xff0c;多应用于工业机器人、数控加工等高精度传动系统中…

【大数据】大数据运维方案浅析总结

1. 引言 在大数据时代&#xff0c;如何高效管理和维护大规模数据平台&#xff0c;成为许多企业面临的重要挑战。本文将对市面上一些流行的大数据运维管理方案进行全面分析&#xff0c;包括Cloudera的CDH和CDP、Hortonworks的HDP、Apache的Ambari、国产开源平台Datasophon&#…

docker使用阿里云镜像加速

官方教程 https://help.aliyun.com/zh/acr/user-guide/accelerate-the-pulls-of-docker-official-images 申请地址 https://free.aliyun.com/?searchKey%E9%95%9C%E5%83%8F 阿里云容器镜像服务地址 https://cr.console.aliyun.com/cn-zhangjiakou/instances 展开才能看到

UNI-SOP应用场景(2)- 业务平台集成

前面介绍了项目前期我们前端可以不需要业务平台参与就可以开始开发&#xff0c;这一章我们介绍新业务平台怎么集成到UNI-SOP云统一认证中心。 新建项目引入uni-client在云认证统一管理端新增业务平台在业务平台项目配置在认证中心创建的平台信息接口开发和权限校验 新建项目 打…

浅谈端到端,助力智能驾驶突破OR错误路线

目前端到端自动驾驶的定义可以简单分为狭义端到端和广义端到端。 狭义端到端&#xff1a;传感器数据进入神经 网络处理后&#xff0c;直接输出方向盘、油门、刹车等执行器的控制信号&#xff0c;该模式通过单一神经网络模型实现&#xff0c;是严格意义上的端到端。 广义端到端&…

基于nodejs+vue的外卖管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…