c++模板初阶

文章目录

  • 前言
  • 一、泛型编程
    • 1、泛型编程
    • 2、函数模板
      • 2.1 函数模板的使用
      • 2.2 函数模板的实例化
      • 2.3 模板参数的匹配原则
    • 3、类模板


前言


一、泛型编程

1、泛型编程

在学习了前面的c++重载之后,我们写一个Swap函数用来交换不同类型的数据时,可以使用函数重载,然后让每个Swap函数的形参不同。

void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}
void Swap(double& x, double& y)
{double tmp = x;x = y;y = tmp;
}
void Swap(char& x, char& y)
{char tmp = x;x = y;y = tmp;
}int main()
{int a1 = 1;int a2 = 2;double d1 = 2.2;double d2 = 3.3;Swap(a1, a2);Swap(d1, d2);return 0;
}

上面代码使用函数重载虽然可以实现,但是有一下几个不好的地方:
1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数。
2. 代码的可维护性比较低,一个出错可能所有的重载均出错。

那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?
c++的泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
在这里插入图片描述

2、函数模板

2.1 函数模板的使用

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
函数模板格式
template<typename T1, typename T2,…,typename Tn>
返回值类型 函数名(参数列表){}
注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)


//template<class T>  //使用class也可以
template<typename T>
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}int main()
{int a1 = 1;int a2 = 2;double d1 = 2.2;double d2 = 3.3;//Swap(a1,a2)和Swap(d1,d2)调用的不是一个函数Swap(a1, a2);Swap(d1, d2);return 0;
}

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器,所以其实Swap(a1,a2)和Swap(d1,d2)不是调用的同一个函数。在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。
在这里插入图片描述

2.2 函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
当我们给Add()中传的实参类型不一致时,就会报错。
该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型,通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T, 编译器无法确定此处到底该将T确定为int 或者 double类型而报错。
注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
在这里插入图片描述
所以此时有两种解决办法:
(1). 用户自己来强制转化 。
即使用强制类型转换来使两个实参的类型一致。
在这里插入图片描述
(2). 使用显式实例化。在函数名后的<>中指定模板参数的实际类型。
使用显示实例化后,编译器就不会再需要推演其实参类型,而是直接将T设为显示设置的类型,这样再调用Add(a1,d1)时,d1会发生隐式类型转换,直接转换为了int类型。但是当实参没有办法发生隐式类型转换时,就会报错。
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。
在这里插入图片描述

2.3 模板参数的匹配原则

一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
当此时进行int的加法时,会先调用专门处理int的加法函数,因为该函数已经有了,不需要根据模板来生成了。


//专门处理int的加法函数
int Add(int left, int right)
{return left + right;
}//通用加法函数
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}int main()
{int a1 = 10;int a2 = 20;//会调用专门处理int的加法函数Add(a1, a2);//如果想调用自动生成的,就可以使用显示实例化Add<int>(a1, a2);return 0;
}

对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。
.需要注意:模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。

//专门处理int的加法函数
int Add(int left, int right)
{return left + right;
}//通用加法函数
template<class T1, class T2>
T1 Add(const T1& left, const T2& right)
{return left + right;
}int main()
{int a1 = 10;int a2 = 20;//会调用专门处理int的加法函数,因为与非模板函数完全匹配,不需要函数模板实例化Add(a1, a2);//与非模板函数不完全匹配,模板函数可以生成更加匹配的版本,所以不会调用非模板函数,//而是会调用编译器根据实参生成的更加匹配的Add函数Add(1, 2.2);return 0;
}

3、类模板

在之前我们写的Stack类中,当我们想要实例化一个存int类型的对象,再实例化一个存double类型的对象时,之前学习的语法是办不到的。

typedef int STDataType;
class Stack
{private:STDataType* _a;size_t _top;size_t _capacity;
};int main()
{Stack st1;  //int Stack st2;  //doublereturn 0;
}

但是当我们使用了类模板后就可以完成上面的要求。
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
并且类模板只能显示实例化。

template<class T>
class Stack
{
public:Stack(int capacity=4){_a = new T[capacity];_top = 0;_capacity = capacity;}~Stack();
private:T* _a;size_t _top;size_t _capacity;
};
//注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Stack<T>::~Stack()
{delete[] _a;_capacity = 0;_top = 0;
}
int main()
{//编译器会生成一个存int类型的类Stack,然后实例化一个对象st1Stack<int> st1;  //int //编译器会生成一个存double类型的类Stack,然后实例化一个对象st2Stack<double> st2;  //doublereturn 0;
}

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

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

相关文章

Learn Prompt-Prompt 高级技巧:AutoGPT

AutoGPT 是一个由Toran Richards创建的流行开源项目。它利用GPT4作为大脑&#xff0c;结合langchain的链接思想&#xff0c;连接各种工具和互联网资源&#xff0c;来完成人类给予的任务。您只需要设定一个目标&#xff0c;AutoGPT就会自主规划并逐步执行任务。如果遇到问题&…

xyhcms getshell

下载xyhcms3.6.2021版本并用phpstudy搭建 function get_cookie($name, $key ) {if (!isset($_COOKIE[$name])) {return null;}$key empty($key) ? C(CFG_COOKIE_ENCODE) : $key;$value $_COOKIE[$name];$key md5($key);$sc new \Common\Lib\SysCrypt($key);$value $sc-…

Zabbix5.0_介绍_组成架构_以及和prometheus的对比_大数据环境下的监控_网络_软件_设备监控_Zabbix工作笔记

z 这里Zabbix可以实现采集 存储 展示 报警 但是 zabbix自带的,展示 和报警 没那么好看,我们可以用 grafana进行展示,然后我们用一个叫睿象云的来做告警展示, 会更丰富一点. 可以看到 看一下zabbix的介绍. 对zabbix的介绍,这个zabbix比较适合对服务器进行监控 这个是zabbix的…

PyTorch框架中torch、torchvision、torchaudio与python之间的版本对应关系(9月最新版)

随着python语言和pytorch框架的更新&#xff0c;torch\torchvision\torchaudio与python之间的版本对应关系也在不断地更新。 最新版本torch与torchvision对应关系如下&#xff1a; 稍旧版本torch与torchvision对应关系如下&#xff1a; 最新版本torch与torchaudio对应关系如下…

计算机竞赛 深度学习 机器视觉 车位识别车道线检测 - python opencv

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) …

如何将视频进行分割?这几种分割方法了解一下

当我们将视频分成几段后&#xff0c;可以更好地组织和管理不同的片段&#xff0c;方便后续查找和使用。我们可以根据需要调整视频的长度和内容&#xff0c;满足不同的观看需求。此外&#xff0c;分段视频可以更好地适应不同的观看场景&#xff0c;可以更方便地分享和传播&#…

【网络协议】Http-上

Http请求结构&#xff1a; 结构图1&#xff1a; 实验解析请求报文&#xff1a; 1.在Edge浏览器上输入ip地址端口号文件资源&#xff0c;也就是下图中的120.XX.139.29:8888/A/B/c.html 2.我的程序接收到了一个没有有效载荷的http请求(呼应上面的结构图1)&#xff0c;如下 GET …

三维模型3DTile格式轻量化在数据存储的重要性分析

三维模型3DTile格式轻量化在数据存储的重要性分析 三维模型3DTile格式轻量化在数据存储中占有重要地位。随着科技的不断发展&#xff0c;尤其是空间信息科技的进步&#xff0c;人们对于三维地理空间数据的需求日益增长。然而&#xff0c;这类数据通常具有大尺度、高精度等特点&…

pip pip3安装库时都指向python2的库

当在python3的环境下使用pip3安装库时&#xff0c;发现居然都指向了python2的库 pip -V pip3 -V安装命令更改为&#xff1a; python3 -m pip install <package>

C++跳坑记:位移超出范围的处理

在C编程中&#xff0c;数据类型的选择不仅影响内存占用和性能&#xff0c;还可以对某些操作的结果产生意想不到的影响。今天&#xff0c;我将分享一个关于C在不同变量类型下位移操作结果的发现。 位移操作是C中常见的对整数的高效操作之一。然而&#xff0c;我们可能会忽视一个…

交换机端口镜像详解

交换机端口镜像是一种网络监控技术&#xff0c;它允许将一个或多个交换机端口的网络流量复制并重定向到另一个端口上&#xff0c;以便进行流量监测、分析和记录。通过端口镜像&#xff0c;管理员可以实时查看特定端口上的流量&#xff0c;以进行网络故障排查、安全审计和性能优…

docker总结

Docker实用篇 0.学习目标 1.初识Docker 1.1.什么是Docker 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&#xff0c;依赖的组件非常多&#xff0c;不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署…

VVICAPI接口解析,实现根据ID取商品详情

VVICAPI是一个虚构的API接口名称&#xff0c;我无法提供具体的VVICAPI接口解析。但是&#xff0c;我可以向您展示一般的API接口使用方法&#xff0c;以及如何根据ID获取商品详情的示例代码。 假设您有一个名为"VVICAPI"的接口&#xff0c;并且您已经获得了访问该接口…

go语言初学(备忘)

1、安装 2 路径配置 C:\Program Files\Go\bin 3新建一个工程 4、下载VSCode 并安装插件 创建一个调试文件 在main目录下新建一个test.go脚本 package main import "fmt" func main() { fmt.Println("Hi 1111") fmt.Println("testasdf") } 断点…

【使用Cpolar将Tomcat网页传输到公共互联网上】

文章目录 1.前言2.本地Tomcat网页搭建2.1 Tomcat安装2.2 配置环境变量2.3 环境配置2.4 Tomcat运行测试2.5 Cpolar安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 Tomcat作为一个轻量级的服务器&#xff0c;不仅名字很有趣&#…

SpringBoot3基础:最简项目示例

说明 本文建立一个最基本的SpringBoot3项目&#xff0c;依赖项仅包含 spring-web&#xff08;SpringMVC&#xff09;。 备注&#xff1a;SpringBoot3需要JDK17支持&#xff0c;配置方法参考&#xff1a; SpringBoot3项目中配置JDK17 项目结构图示 POM <?xml version&qu…

解决qml编译时出现错误ninja: build stopped: subcommand failed.

qml编译时出现错误ninja: build stopped: subcommand failed. 如下图&#xff1a; 解决这个编译错误其实很简单&#xff0c;我把Window写错了&#xff0c;写成了window, 如果有类似的报错&#xff0c;可以检查一下qml代码是否有问题。当然在Qt Creator里也没有错误提示&#x…

Redis 面试常见问答

本文出自&#xff1a;https://thinkinjava.cn 作者&#xff1a;莫那 鲁道 1. 什么是缓存雪崩&#xff1f;怎么解决&#xff1f; 一般而言&#xff0c;我们会利用缓存来缓冲对数据库的冲击&#xff0c;假如缓存无法正常工作&#xff0c;所有的请求便会直接发送至数据库&#xf…

hadoop3.x搭建到集群调优

一、基础环境安装 https://blog.csdn.net/fen_dou_shao_nian/article/details/120945221 二、hadoop运行环境搭建 2.1 模板虚拟机环境准备 0&#xff09;安装模板虚拟机&#xff0c;IP 地址 192.168.10.100、主机名称 hadoop100、内存 4G、硬盘 50G 1&#xff09;hadoop100…

字符串函数

目录 一、求字符串长度 strlen 用法&#xff1a; 注意&#xff1a; 二、长度不受限制的字符串函数 strcpy 用法&#xff1a; 注意&#xff1a; strcat 用法&#xff1a; 注意&#xff1a; 用例&#xff1a; strcmp 用法&#xff1a; 三、长度受限制的字符串函数介…