第四章:C++模板初阶

news2025/1/11 6:12:02

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 泛型编程
  • 函数模板
    • 函数模板概念
  • 函数模板格式
    • 函数模板的原理
    • 函数模板的实例化
    • 模板参数的匹配原则
  • 类模板
    • 类模板的定义格式
    • 类模板的实例化
  • 总结


前言

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

使用函数重载虽然可以实现,但是有一下几个不好的地方:

  1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数

  2. 代码的可维护性比较低,一个出错可能所有的重载均出错

那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

在这里插入图片描述

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

在这里插入图片描述

函数模板

函数模板概念

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

函数模板格式

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

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

注意:typename是用来定义模板参数关键字也可以使用class(切记:不能使用struct代替class)

函数模板的原理

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器

在这里插入图片描述

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此

函数模板的实例化

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

  1. 隐式实例化:让编译器根据实参推演模板参数的实际类型
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, a2);
	Add(d1, d2);
	/*
	该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
	通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,
	编译器无法确定此处到底该将T确定为int 或者 double类型而报错
	注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
	Add(a1, d1);
	*/
	// 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
	Add(a, (int)d);
	return 0;
}
  1. 显式实例化:在函数名后的<>中指定模板参数的实际类型
int main(void)
{
	int a = 10;
	double b = 20.0;
	// 显式实例化
	Add<int>(a, b);
	return 0;
}

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

模板参数的匹配原则

  1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
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;

总结

C++通过泛型编程来实现函数模板和类模板,以此来实现不同类型的函数和类型。
人生如逆旅,我亦是行人。——苏轼

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

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

相关文章

图像分割的简史:从CNN到掩模R-CNN

一、说明 在 Athelas&#xff0c;我们使用卷积神经网络 &#xff08;CNN&#xff09; 不仅仅是分类&#xff01;在这篇文章中&#xff0c;我们将看到如何在图像实例分割中使用CNN&#xff0c;并取得很好的效果。 自从 Alex Krizhevsky、Geoff Hinton 和 Ilya Sutskever 在 2012…

Windows bat实现删除文本中的 空行、空格、制表符、最后一行空行

文章目录 一、准备测试数据二、通过for /f实现1. 删除仅含换行符的空行2. 删除所有空白行3. 删除所有空白行以及非空白行左侧的空格和制表符4. 删除所有空白行以及非空白行两侧的空格和制表符5. 删除所有空白行以及所有空格和制表符 三、通过findstr实现1. 删除仅含换行符的空行…

Base64存储为文件

要将Base64编码的字符串存储为文件&#xff0c;您可以按照以下步骤进行操作&#xff1a; 将Base64编码的字符串解码为字节数组。您可以使用Java的Base64类进行解码&#xff0c;例如&#xff1a; import java.util.Base64;String base64String "your_base64_encoded_str…

unity 打包htv vive 客户端包,调不出SteamVR

原因一&#xff1a; 引用自&#xff1a;unity 运行包无法连接SteamVR问题_野区捕龙为宠的博客-CSDN博客 原因二&#xff1a; 1、打包出来的exe文件命名是中文名&#xff0c;如&#xff1a;危化品.exe 2、打包路径中有中文。 避免以上情况即可。 引用自&#xff1a;unity 打包…

算法训练营第三十八天||● 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯

● 理论基础 五步走&#xff1a; 确定dp数组 递推公式 dp数组初始化 遍历顺序 打印dp数组 ● 509. 斐波那契数 这道题比较简单&#xff0c;但自己不看答案还做不出来&#xff0c;没想到用初始的方法 先看递归 只需要两行代码 确定终止条件 和逻辑 class Solution { p…

Java-API简析_java.lang.Process类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/131714752 出自【进步*于辰的博客】 因为我发现目前&#xff0c;我对Java-API的学习意识比较薄弱…

软考A计划-系统集成项目管理工程师--项目质量管理-尾

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

【FAQ】API6低代码开发问题汇总

参考文档&#xff1a; 低代码开发参考文档&#xff1a; 文档中心:使用低代码进行开发 基于景区模板开发元服务&#xff1a; 文档中心:模板简介 使用API6低代码开发遇到的问题汇总情况如下&#xff1a; 1、低代码环境下&#xff0c;如何实现box-shadow阴影效果的配置&#…

第五章:DeepLabV1——深度卷积神经网络和全连接条件随机场的语义图像分割

0.摘要 深度卷积神经网络&#xff08;DCNN&#xff09;在图像分类和目标检测等高级视觉任务中表现出最先进的性能。本研究结合了DCNN和概率图模型的方法&#xff0c;用于解决像素级分类的任务&#xff08;也称为“语义图像分割”&#xff09;。我们发现&#xff0c;DCNN最后一层…

sping boot与JPA结合使用

1、pom.xml文件内容如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http:/…

SOPC之NiosⅡ系统(二)

常用NIOS Ⅱ组件概括 目录 1.时钟组件 2.Nios Ⅱ处理器 2.1 Main 2.2 Vector 2.3 Caches and Memory Interfaces 2.4 Arithmetic Instructions 2.5 JTAG Debug 3.RAM组件 4.System ID组件 5.JTAG UART组件 6.PIO组件 6.1 基础设置(Basic Settings) 6.2 输出寄存器…

应用于智能眼镜上实现检测功能的距离传感芯片

随着智能穿戴设备的发展&#xff0c;各种新型的电子产品不断被研发出来&#xff0c;诸如智能头盔、智能手表、智能手环等等&#xff0c;智能眼镜就是其中一种&#xff0c;国内华为、小米相继推出智能产品。 智能眼镜具有和智能耳机相似的功能&#xff0c;不仅保留眼镜本身功能…

Twitter迎来史上最大危机,超级App能成为其救命武器吗?

前段时间闹得沸沸扬扬的“马扎大战”再出新剧情&#xff0c;继“笼斗”约架被马斯克妈妈及时叫停之后&#xff0c;马斯克在7月9日再次向扎克伯克打起嘴炮&#xff0c;这次不仅怒骂小扎是混蛋&#xff0c;还要公开和他比大小&#xff1f;&#xff01;&#xff01;此番马斯克的疯…

应用开发环境搭建

应用开发环境搭建 1、安装JDK linux上传安装包解压缩设置环境变量判断JDK是否安装成功 2、nginx下载选择Stable version版本下载到本地&#xff08;该版本为Linux版本&#xff09;&#xff0c;下载完成后直接在本地解压后放入linux系统中下载完成后&#xff0c;安装Nginx&#…

android studio 使用lib中的framework.jar编译

本文参考了网上搜索到的内容总结了一下&#xff0c;感谢大神们的无私奉献。 在App中的build.gradle中的android{}下添加&#xff1a; android{...gradle.projectsEvaluated {tasks.withType(JavaCompile) {Set<File> fileSet options.bootstrapClasspath.getFiles()Li…

想知道音频转文字怎么弄吗?看完这篇文章你就懂了

小伙伴们&#xff0c;你们有没有遇到过这样的情况&#xff1a;听到了一段有趣或重要的音频&#xff0c;但却无法方便地保存下来或与他人分享&#xff1f;别担心&#xff0c;现在有很多免费的音频转文字软件app可以帮助我们解决这个问题。不过&#xff0c;这些音频转文字软件app…

S32K系列MCU介绍和资料搜集

1. S32K系列微控制器概述 S32K系列微控制器&#xff0c;是NXP推出的专门面向汽车电子和工业应用场合的微控制器。基于ArmCortex-M系列的可扩展、低功耗微控制器&#xff0c;获得了AEC-Q100认证&#xff0c;具有高级功能安全、信息安全和软件支持&#xff0c;适用于工业和汽车A…

进程间通信之匿名管道(pipe)

文章目录 前言管道管道的创建管道的使用单进程使用管道进行通信多进程使用管道进行通信关闭管道的读端/写端 总结 前言 管道分为匿名管道和命名管道&#xff0c;匿名管道只能在有共同祖先的(有亲缘关系)进程中使用&#xff0c;而命名管道可以在任意进程中使用&#xff0c;以下…

【youcans动手学模型】目标检测之 OverFeat 模型

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans 【youcans动手学模型】目标检测之 OverFeat 模型 1. OverFeat 卷积神经网络模型1.1 论文摘要1.2 技术背景1.3 基本方法模型设计多尺度分类滑动窗口&#xff08;Sliding window&#xff09;定位&#…

ACL—访问控制列表

目录 ACL的分类&#xff1a; 配置 配置基础ACL &#xff1a; 例一&#xff1a; 例二&#xff1a; 配置高级ACL &#xff1a; 例一&#xff1a; 例二&#xff1a; ACL—访问控制列表 配置了ACL的网络设备根据事先制定号的规则&#xff0c;然后对经过该设备的流量按照对应的规…