当前位置: 首页 > news >正文

C++ 函数模板与类模板

C++最重要的特性之一就是代码重用,为了实现代码重用,代码必须具有通用性。通用代码应不受数据类型的影响,并且可以自动适应数据类型的变化。这种程序设计类型称为参数化程序设计。模板是C++支持参数化程序设计的工具,通过它可以实现参数化多态性。所谓参数化多态性,就是将程序所处理的对象的类型参数化,使得一段程序可以用于处理多种不同类型的对象。

1.函数模板

通过函数重载,可以看出重载函数通常是对于不同的数据类型完成类似的操作。很多情况下,一个算法是可以处理多种数据类型的。但是用函数实现算法时,即使设计为重载函数也只是使用相同的函数名,函数体仍然要分别定义。

下面是两个求绝对值的函数:

int abs(int x)
{return x < 0 ? -x : x;
}double abs(double x)
{return x < 0 ? -x : x;
}

这两个函数只有参数类型和返回类型不同,功能完全一样。类似这样的情况,我们需要写一段通用的代码是用于多种不同的数据类型,这样会使代码的可重用性大大提高,从而提高软件的开发效率。使用函数模板就是为了达到这一目的。程序员只对函数模板编写一次,然后基于调用函数时提供的参数类型,C++编译器将自动产生相应的函数来正确地处理该类型的数据。

(1)函数模板的定义形式为
template <模板参数表>
类型名 函数名(参数表)
{函数体定义
}

所有函数模板的定义都是用关键字template开始的,该关键字之后是用尖括号<>括起来的“模板参数表”。模板参数表由用逗号隔开的模板参数构成,可以包括以下内容:

①class(或typedef)标识符,指明可以接收一个类型参数。这些类型参数代表的是类型,可以是内部类型或者自定义类型。
②“类型说明符”标识符,指明可以接收一个由“类型说明符”所规定类型的常量作为参数。
③template<参数表>class标识符,指明可以接收一个类模板名作为参数。

类型参数可以用来指定函数模板本身的形参类型、返回值类型,以及声明函数中的局部变量。函数模板中函数体的定义方式与定义普通函数类似。

【例1】求绝对值的函数模板

template<class T>
T abs(T x)
{return x < 0 ? -x : x;
}
int main()
{int n = -5;cout << abs(n) << endl;double m = -6.8;cout << abs(m) << endl;return 0;
}

运行结果:
在这里插入图片描述
分析:

①在上述主函数中调用abs()时,编译器从实参的类型推导出函数模板的类型参数。

②当类型参数的含义确定后,编译器将以函数模板为样板,生成一个函数,这一过程称为函数模板的实例化。

例如,对于调用表达式abs(n),由于实参n是int类型,所以推导出函数模板中类型参数T为int,接着,编译器以函数模板为样板,生成如下函数,该函数为函数模板abs的一个实例:

int abs(int x)
{return x < 0 ? -x : x;
}

同样,对于调用表达式abs(m),由于实参m是double型,所以推导出函数模板中类型参数T为double,接着,编译器以函数模板为样板,生成如下函数:

double abs(double x)
{return x < 0 ? -x : x;
}

③因此,当主函数第一次调用abs时,执行的实际上是由函数模板生成的函数int abs(int x);,主函数第二次调用abs时,执行的实际上是由函数模板生成的函数double abs(double x);

【例2】函数模板示例

template<class T>
void outputA(const T* arr, int n)
{for (int i = 0;i < n; i++){cout << arr[i] << " ";}cout << endl;
}int main()
{const int A_n = 5;const int B_n = 6;const int C_n = 7;int arr[A_n] = { 1,2,3,4,5 };cout << "输出数组arr的内容:" << "   ";outputA(arr, A_n);double brr[B_n] = { 1.1,2.2,3.3,4.4,5.5,6.6 };cout << "输出数组brr的内容:" << "   ";outputA(brr, B_n);char crr[C_n] = "Hi yyn";cout << "输出数组crr的内容:" << "   ";outputA(crr, C_n);return 0;
}

运行结果:
在这里插入图片描述
分析:

函数模板中声明了类型参数T,表示一种抽象的类型。当编译器检测到程序中调用函数模板outputA时,便用outputA的第一个实参的类型替换掉整个模板定义中的T,并建立用来输出指定类型数组的一个完整的函数,然后再编译这个新建的函数。

主函数中声明了3中不同类型的数组,int型数组arr,double型数组brr和char型数组crr,长度分别为5,6,7。然后调用函数模板生成相应的函数,最后在屏幕上输出每个数组。编译过程中针对3种数据类型生成的函数如下:

outputA(a,A_n);//适用于int类型的outputA模板函数
outputA(b,B_n);//适用于double类型的outputA模板函数
outputA(c,C_n);//适用于char类型的outputA模板函数

由上例可以看出,模板函数与重载密切相关。从函数模板产生的相关函数都是同名的,编译器用重载的方法调用相应的函数。另外函数模板本身也可以用多种方法重载。

(2)模板函数的使用形式和函数的本质区别

①函数模板本身在编译时不会生成任何目标代码,只有由模板生成的实例会生成目标代码。

②被多个源文件引用的函数模板,应当连同函数体一同放在头文件中,而不能像普通函数那样只将声明放在头文件中。

③函数指针也只能指向函数模板的实例,而不能指向函数模板本身。

2.类模板

使用类模板使用户可以为类定义一种模式,使得类中的某些数据成员、某些成员函数的参数、返回值或局部变量能取任意类型(包括系统预定义的和用户自定义的)。

类是对一组对象的公共性质的抽象,而类模板则是对不同类的公共性质的抽象,因此,类模板是属于更高层次的抽象。由于类模板需要一种或多种类型参数,所以类模板也常常称为参数化类。

(1)类模板声明的语法形式
template<模板参数表>
class 类名
{类成员声明;
};

其中类成员的声明方法和普通类的定义几乎相同,只是它的各个成员(数据成员和函数成员)中通常要用到模板的类型参数T。其中“模板参数表”的形式与函数模板中的“模板参数表”相同。

如果需要在类模板以外定义其成员函数,则要采用以下的形式:

template<模板参数表>
类型名 类名<模板参数标识符列表>::函数名(参数表)

一个类模板声明,其自身并不是一个类,它说明了类的一个家族,只有被其他代码引用时,类模板才根据引用的需要生成具体的类。类模板的实例化过程在程序中时隐藏的。

使用一个类模板建立对象时,应以如下形式声明:

模板名<模板参数表>对象名1,...,对象名n;

【例】类模板应用举例
在本例中,声明一个实现任意类型数据存取的类模板S,然后通过具体数据类型参数对类模板进行实例化,生成类,然后类在被实例化生成对象s1,s2,s3和d。

struct student//结构体student
{int id;//学号float avg;//平均分
};template<class T>//类模板:实现对任意类型数据进行存取
class S
{
private:T item;//用于存放任意类型的数据bool Isvalue;//标记item是否被存入
public:S();//默认构造函数T& getE();//提取数据函数void putE(const T& x);//存入数据函数
};template<class T>//默认构造函数的实现
S<T>::S():Isvalue(false){}template<class T>//提取数据函数的实现
T&S<T>::getE()
{	if (!Isvalue)//如果提取的是没有初始化的数据,则程序终止{cout << "数据不存在" << endl;exit(1);//使程序完全退出,返回到操作系统//参数可用来表示程序终止的原因,可以被操作系统接收}elsereturn item;//返回item中存放的数据
}template<class T>//存入函数的实现
void S<T>::putE(const T& x)
{Isvalue = true;//将Isvalue设置为true,表示item中已存入数值item = x;//将x的值存入item
}int main()
{S<int>s1, s2;//定义两个S<int>类对象s1和s2,其中数据成员item为int型s1.putE(3);//向对象s1中存入数据(初始化对象s1为3)s2.putE(-7);//向对象s2中存入数据(初始化对象s1为-7)cout << s1.getE() << " " << s2.getE() << endl;//输出对象s1和s2的数据成员student g = { 1000,23 };//定义student类型结构体变量的同时赋予初值S<student>s3;//定义S<student>类对象s3,其中数据成员item为student类型s3.putE(g);//向对象s3中存入数据(初始化对象s3)cout << "这个学生的id是" << s3.getE().id << endl;//输出对象s3的数据成员S<double>d;//定义S<double>类对象d,其中数据成员item为double类型cout << "检索对象d";cout << d.getE() << endl;//输出对象d的数据成员//由于对象d未经初始化,在执行函数d.getE()过程中导致程序终止return 0;
}

运行结果:
在这里插入图片描述

相关文章:

C++ 函数模板与类模板

C最重要的特性之一就是代码重用&#xff0c;为了实现代码重用&#xff0c;代码必须具有通用性。通用代码应不受数据类型的影响&#xff0c;并且可以自动适应数据类型的变化。这种程序设计类型称为参数化程序设计。模板是C支持参数化程序设计的工具&#xff0c;通过它可以实现参…...

Tailwind CSS:简洁高效的工具,提升前端开发体验

112. Tailwind CSS&#xff1a;简洁高效的工具&#xff0c;提升前端开发体验 1. 什么是Tailwind CSS&#xff1f; Tailwind CSS是由Adam Wathan、Jonathan Reinink、David Hemphill和Steve Schoger等人共同创建的一种现代CSS框架。与传统的CSS框架不同&#xff0c;Tailwind CS…...

NR CSI(六) CSI reporting using PUCCH

之前NR CSI(二) the workflow of CSI report有对CSI report的相关流程进行介绍&#xff0c;而这篇主要看下CSI reporting over PUCCH的相关规定。 CSI report在PUCCH上传输的场景如上表红色字体&#xff0c;有三种场景&#xff0c;具体的对应的是Periodic 和Semi-Persistent CS…...

论文阅读---《Unsupervised Transformer-Based Anomaly Detection in ECG Signals》

题目&#xff1a;基于Transformer的无监督心电图&#xff08;ECG&#xff09;信号异常检测 摘要 异常检测是数据处理中的一个基本问题&#xff0c;它涉及到医疗感知数据中的不同问题。技术的进步使得收集大规模和高度变异的时间序列数据变得更加容易&#xff0c;然而&#xff…...

5G上行干扰规避的参数策略

LNR干扰避让 1. 干扰避让特性 D1/D2干扰避让&#xff1a;干扰与非干扰带宽独立测量&#xff0c;避免部分频带受干扰拉低整个带宽MCS&#xff0c;基于测量结果&#xff0c; 用户级自适应调度60/80/100M&#xff0c;躲避干扰频带。 窄带干扰避让&#xff1a;避免部分带宽的干扰对…...

CTF流量题解tcp1

用流量工具进行分析。发现消息长度有点异常。右键TCP跟踪。 ....mos.-mos-.-.mos-.-mos..-.mos..-mos-. 摩斯密码生成-网页工具 (adminun.com)...

Django快速入门

文章目录 一、安装1.创建虚拟环境&#xff08;virtualenv和virtualenvwrapper&#xff09;2. 安装django 二、改解释器三、创建一个Django项目四、项目目录项目同名文件夹/settings.py 五、测试服务器启动六、数据迁移七、创建应用八、基本视图1. 返回响应 response2. 渲染模板…...

Python “牵手” 淘宝商品详情数据获取方法,淘宝API申请指南

淘宝详情接口 API 是淘宝开放平台提供的一种 API 接口&#xff0c;它可以帮助开发者获取淘宝商品的详细信息&#xff0c;包括商品的标题、描述、图片等信息。在淘宝电商平台的开发中&#xff0c;淘宝详情接口 API 是非常常用的 API&#xff0c;因此本文将详细介绍淘宝详情接口 …...

OpenScene

paper:OpenScene: 3D Scene Understanding with Open Vocabularies code: https://github.com/pengsongyou/openscene 摘要:传统的3D场景理解方法依赖于带标签的3D数据集,在有监督的情况下为单个任务训练模型。我们提出了OpenScene,一种替代性的方法,模型预测CLIP特征空…...

HDFS中的Trash垃圾桶回收机制

Trash垃圾桶回收机制 文件系统垃圾桶背景功能概述Trash Checkpoint Trash功能开启关闭HDFS集群修改core-site.xml删除文件到trash删除文件跳过从trash中恢复文件清空trash 文件系统垃圾桶背景 回收站&#xff08;垃圾桶&#xff09;是windows操作系统里的一个系统文件夹&#…...

segment-anything使用说明

文章目录 一. segment-anything介绍二. 官网Demo使用说明三. 安装教程四. python调用生成掩码教程五. python调用SAM分割后转labelme数据集 一. segment-anything介绍 Segment Anything Model&#xff08;SAM&#xff09;根据点或框等输入提示生成高质量的对象遮罩&#xff0c…...

在魔塔社区搭建通义千问-7B(Qwen-7B)流程

复制以下语句 python3 -m venv myvenvsource myvenv/bin/activatepip install modelscope pip install transformers_stream_generator pip install transformers pip install tiktoken pip install accelerate pip install bitsandbytestouch run.py vi run.py复制下面代码粘…...

Redis 加入服务列表自启动

1、下载reids windows版本&#xff0c;选择zip格式下载 2、解压zip&#xff0c;并进入路径&#xff1b; 3、命令提示符&#xff08;cmd&#xff09; 进入解压后的路径后&#xff0c;输入指令&#xff1a;redis-server --service-install redis.windows.conf&#xff1b; 4、如…...

MyCat管理及监控——zookeeper及MyCat-web安装

1.MyCat管理 2.MyCat-eye 3.zookeeper安装 第一步&#xff1a;解压 第二部&#xff1a; 切换目录&#xff0c;创建data文件夹 第三步&#xff1a;修改zookeeper配置文件 这样zookeeper安装及配置就完成了 4.MyCat-web安装 注意mycat-web要与zookeeper关联&#xff0c;…...

基于spring boot的餐饮管理系统java酒店饭店菜谱 jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于spring boot的餐饮管理系统j 系统1权限&#xff…...

JVM分析工具JProfiler介绍及安装

目录 一、什么是JProfiler&#xff1f; 二、JProfiler 功能结构 1、分析代理 2、记录数据 3、快照 三、安装 一、什么是JProfiler&#xff1f; JProfiler是一个专业的工具&#xff0c;用于分析运行中的JVM内部发生的事情。当您的生产系统出现问题时&#xff0c;您可以…...

Nginx使用多个.conf文件配置虚拟主机server

使用 Nginx 配置多个虚拟机 server 服务。通常做法可以直接在 nginx.conf 文件中添加即可&#xff0c;如下事例&#xff1a; # nginx.confworker_processes 1;events {worker_connections 1024; }http {include mime.types;default_type application/octet-stream…...

nginx编译以及通过自定义生成证书配置https

1. 环境准备 1.1 软件安装 nginx安装编译安装以及配置https&#xff0c;需要gcc-c pcre-devel openssl openssl-devel软件。因此需要先安装相关软件。 yum -y install gcc-c pcre-devel openssl openssl-devel wgetopenssl/openssl-devel&#xff1a;主要用于nginx编译的htt…...

OpenAI 已为 GPT-5 申请商标,GPT-4 发布不到半年,GPT-5 就要来了吗?

据美国专利商标局&#xff08;USPTO&#xff09;信息显示&#xff0c;OpenAI已经在7月18日申请注册了“GPT-5”商标。 在这份新商标申请中&#xff0c;OpenAI将“GPT-5”描述为一种“用于使用语言模型的可下载计算机软件”。 继GPT-4发布之后&#xff0c;它预计将成为OpenAI下一…...

【Linux】深入理解进程概念

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;Linux仓库 个人专栏&#xff1a;Linux专栏 分享一句喜欢的话&#xff1a;热烈的火焰&#xff0c;冰封在最沉默的火山深处 文章目录 前言浅谈进程概念1. 进程和操作系统的联系2.描述进程的对象——PCB …...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

高考志愿填报管理系统---开发介绍

高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发&#xff0c;采用现代化的Web技术&#xff0c;为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## &#x1f4cb; 系统概述 ### &#x1f3af; 系统定…...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...