C++:模版初阶

news2024/12/25 12:15:06

 

目录

1. 泛型编程

2.函数模版 

2.1. 函数模版的用法 

2.2. 函数模版的原理 

2.3 函数模板的实例化 

2.4 模版参数的匹配原则 

3. 类模版 

3.1 类模版的格式 

3.2. 类模版的实例化 


1. 泛型编程

如何实现整形、字符串,或者其他自定义类型的交换函数? 

 

我们可以利用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. 代码的可维护性比较低,一个出错可能所有的重载均出错 

为了解决这个问题,C++就引入了模版这个概念,并且依次延伸出了泛型编程的思想。**泛型编程:**编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。 

模版简单来说就是像一个道具模子,根据不同的需求,可以产生不同的形态。而模版即可以分为函数模版,又可以分为类模版。 

2.函数模版 

2.1. 函数模版的用法 

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

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

然后我们就可以用模版定义一个针对不同类型的交换函数: 

#include<iostream>
using namespace std;
template<typename T>
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	int a = 1;
	int b = 2;
	double n = 1.1;
	double m = 2.2;
	cout << "交换前:" << a << "," << b << endl << endl;
	cout << "交换前:" << n << "," << m << endl << endl;
	Swap(a, b);
	Swap(n, m);
	cout << "交换后:" << a << "," << b << endl;
	cout << "交换后:" << n << "," << m << endl;
}

 

  • 注意:typename是用来定义模板参数关键字,也可以使用class
2.2. 函数模版的原理 

学会了如何使用函数模版之后,我们就可能会有一个疑问:那就是不同的类型调用的函数模版是同一个函数吗?这时我们继续利用上面代码,通过调用汇编来观察一下: 

 

函数的指令并不一样,这说明调用的根本不是同一个函数!!那原理究竟是怎样的呢?

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

 

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

2.3 函数模板的实例化 

 2.3.1. 隐式实例化

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	//编译器自动推导类型
	cout << (Add(3, 5)) << endl;
	return 0;
}

2.3.2. 显示实例化 

但是有些场景下就不能利用隐式实例化的方式调用函数模版,比如说: 

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a = 1;
	double b = 1.1;
	cout << (Add(a, b)) << endl;
	return 0;
}

 

这时编译器就会报错,因为编译器不知道该将T推演成int还是double。为了解决这个问题,就需要让编译器提前知道该将T推演成什么类型,常见有两种解决方法: 

一种方法就是先强制类型转换: 

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a = 1;
	double b = 1.1;
	cout << (Add(a, (int)b)) << endl;
	return 0;
}

 

还要一种方式就是显示实例化:在函数名后的<>中指定模板参数的实际类型。 

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a = 1;
	double b = 1.1;
	cout << (Add<int>(a, b)) << endl;//指定T实例化为int型
	return 0;
}

  int转double还好点,double转int会造成精度丢失 

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

除了以上场景需要显式实例化外,还有一种场景也需要我们显式实例化: 

2.4 模版参数的匹配原则 
  1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
// 专门处理int的加法函数
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
	cout << "T Add(T left, T right)" << endl;
	return left + right;
}
void Test()
{
	Add(1, 2); // 与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2); // 调用编译器特化的Add版本
}

 

 

如果有普通函数可以匹配,那么就不会去调用模版函数,但如果我们非得使用模版的Add函数,只需要进行显示实例化即可! 

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

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

 

3. 类模版 

类模版与函数模版类似,只不过作用对象为类。 

3.1 类模版的格式 

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

template<class T>
class AA
{
public:
	AA(T a1, T a2)
		:_a1(a1),_a2(a2)
	{
		;
	}
	T Add();
private:
	T _a1;
	T _a2;
};
  • 注意:类模板中函数放在类外进行定义时,需要加模板参数列表

模版的声明和定义不能放在不同的文件里,应该统一放在头文件里最合适。 

 

3.2. 类模版的实例化 

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。所以利用类模版创建对象时必须要对类模版先显式实例化。 

void Test()
{
	//创建对象时必须要先实例化
	AA<int> p1(1,2);
	AA<double> p2(1.1,2.2);
}

注意:AA类名AA<double>才是类型 

 

 

 

 

 

 

 

 

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

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

相关文章

Unity AnimationClip详解(2)——动画数据的优化

【内存优化】 首先要意识到运行时和编辑时的区别&#xff0c;当运行时和编辑时所需的数据相差不大时&#xff0c;我们用同一套数据结构即可&#xff0c;当两者差异较多或者数据量很大时&#xff0c;需要有各自的数据结构&#xff0c;这意味着在打包或构建时需要将编辑时数据转…

Android Framework关闭触摸振动

文章目录 手势上滑时振动代码performHapticFeedback作用和意义 触摸振动开关设置Framework关闭触摸时振动 手势上滑时振动代码 安卓手机由底部往上滑时&#xff0c;会有震动&#xff0c;然后进入Recents多任务&#xff0c;其触发震动调用的代码 packages/apps/Launcher3/quick…

LCD手机屏幕高精度贴合

LCD手机屏幕贴合&#xff0c;作为智能手机生产线上至关重要的一环&#xff0c;其质量直接关乎用户体验与产品竞争力。这一工艺不仅要求屏幕组件间的无缝对接&#xff0c;达到极致的视觉与触觉效果&#xff0c;还需确保在整个生产过程中&#xff0c;从材料准备到最终成品&#x…

robots协议ctf

robots协议 Robots协议&#xff0c;全称为“网络爬虫排除标准”(Robots Exclusion Protocol)&#xff0c;是互联网上用于指导搜索引擎蜘蛛如何抓取和访问网站的一种协议。网站可以通过Robots协议告诉搜索引擎哪些页面可以抓取&#xff0c;哪些页面不能抓取&#xff0c;从而保护…

神经架构搜索:自动化设计神经网络的方法

在人工智能&#xff08;AI&#xff09;和深度学习&#xff08;Deep Learning&#xff09;快速发展的背景下&#xff0c;神经网络架构的设计已成为一个日益复杂而关键的任务。传统上&#xff0c;研究人员和工程师需要通过经验和反复试验来手动设计神经网络&#xff0c;耗费大量时…

怿星科技薛春宇丨智能汽车软件研发工具链国产化的挑战和探索

2024年7月25日&#xff0c;由上海良益企业管理咨询有限公司主办的“2024域控制器技术论坛“在上海成功举办&#xff0c;十位嘉宾做了精彩分享。“整零有道”将陆续刊出部分演讲的文字实录&#xff0c;以飨读者。 本期刊出怿星科技副总经理薛春宇的演讲实录&#xff1a;智能汽车…

react-signature-canvas 实现画笔与橡皮擦功能

react-signature-canvas git 地址 代码示例 import React, { Component } from react import { createRoot } from react-dom/clientimport SignaturePad from ../../src/index.tsximport * as styles from ./styles.module.cssclass App extends Component {state { trimmed…

sheng的学习笔记-AI基础-正确率/召回率/F1指标/ROC曲线

AI目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 分类准确度问题 假设有一个癌症预测系统&#xff0c;输入体检信息&#xff0c;可以判断是否有癌症。如果癌症产生的概率只有0.1%&#xff0c;那么系统预测所有人都是健康&#xff0c;即可达到99.9%的准确率。 但显然这样的…

多款云存储平台存在安全漏洞,影响超2200万用户

据苏黎世联邦理工学院研究人员Jonas Hofmann和Kien Tuong Turong的发现&#xff0c;端到端加密&#xff08;E2EE&#xff09;云存储平台存在一系列安全问题&#xff0c;可能会使用户数据暴露给恶意行为者。在通过密码学分析后&#xff0c;研究人员揭示了Sync、pCloud、Icedrive…

方形件排样优化与订单组批问题探析

方形件排样优化与订单组批问题是计算复杂度很高的组合优化问题&#xff0c;在工业工程中有很广泛的应用背景。为实现个性化定制生产模式&#xff0c;企业会选择订单组批的方式&#xff0c;继而通过排样优化实现批量切割&#xff0c;加工完成后再按照不同客户需求进行分拣&#…

洛谷 P1226:【模板】快速幂

【题目来源】https://www.luogu.com.cn/problem/P1226【题目描述】 给你三个整数 a&#xff0c;b&#xff0c;p&#xff0c;求 a^b mod p。【输入格式】 输入只有一行三个整数&#xff0c;分别代表 a&#xff0c;b&#xff0c;p。【输出格式】 输出一行一个字符串 a^b mod ps&a…

多线程——线程池

目录 前言 一、什么是线程池 1.引入线程池的原因 2.线程池的介绍 二、标准库中的线程池 1.构造方法 2.方法参数 &#xff08;1&#xff09;corePoolSize 与 maximumPoolSize &#xff08;2&#xff09;keepAliveTime 与 unit &#xff08;3&#xff09;workQueue&am…

GPT-4o 和 GPT-4 Turbo 模型之间的对比

GPT-4o 和 GPT-4 Turbo 之间的对比 备注 要弄 AI &#xff0c;不同模型之间的对比就比较重要。 GPT-4o 是 GPT-4 Turbo 的升级版本&#xff0c;能够提供比 GPT-4 Turbo 更多的内容和信息&#xff0c;但成功相对来说更高一些。 第三方引用 在 2024 年 5 月 13 日&#xff0…

HTB:Blocky[WriteUP]

目录 连接至HTB服务器并启动靶机 使用nmap对靶机进行端口扫描 再次使用nmap对靶机开放端口进行脚本、服务信息扫描 对FTP服务版本&#xff1a;ProFTPD_1.3.5进行漏洞扫描 对SSH服务版本&#xff1a;OpenSSH 7.2p2进行漏洞扫描 使用浏览器访问靶机80端口 使用浏览器访问U…

信息搜集-域名信息收集

1.1 域名信息收集 WHOIS查询&#xff1a; 通过WHOIS查询可以快速得到域名的IP段、DNS解析、注册时间、地址等信息&#xff0c;或许运用合理可以巧妙的绕过CDN。备案信息收集&#xff1a; 网站备案信息收集更加方便定位资产到具体的企业名称、ICP备案号、备案人名称、公司、所处…

图片写入GPS经纬高信息

近期项目中需要往java平台传输图片&#xff0c;直接使用QNetworkAccessManager和QHttpMultipart类即可&#xff0c;其他博文中有分享。 主要是平台接口对所传输图片有要求&#xff1a;需要包含GPS信息&#xff08;经度、纬度、高度&#xff09;。 Qt无法直接实现&#xff0c;…

2003年秋季我给哈工大数学研究生写的讲义

我写的没出版讲义共有278页&#xff0c;书末参考文献 我写的讲义书末索引&#xff0c;冯克勤的书《代数数论》书末没有索引&#xff0c;陆洪文、李云峰的书《模形式讲义》书末也有索引 我写的讲义自制的封面 &#xff08;对数学的研究我的经验是&#xff0c;跟其他科学类似&am…

「Qt Widget中文示例指南」如何实现半透明背景?

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文将为大家展示如…

Java应用程序的服务器有哪些

1.Tomcat、Jetty 和 JBoss 区别&#xff1f; Apache Tomcat、Jetty 和 JBoss都是用于部署Java应用程序的服务器&#xff0c;它们都支持Servlet、JSP和其他Java EE&#xff08;现在称为Jakarta EE&#xff09;技术。尽管它们有一些相似的功能&#xff0c;但它们之间还是存在一些…

Mysql在线修改表结构工具gh-ost使用说明及实践

本文内容较多&#xff0c;篇幅较长&#xff0c;若不想了解ghost原理&#xff0c;几种模式的介绍以及具体的验证过程&#xff0c;可直接跳到‘四 gh-ost使用总结’查看简洁版使用说明。 一 gh-ost使用场景 生产环境当有关于一个大表的大操作时(比如select count一个大表)&…