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

C++初阶:入门泛型编程(函数模板和类模板)

大致介绍了一下C/C++内存管理、new与delete后:C++初阶:C/C++内存管理、new与delete详解
我们接下来终于进入了模版的学习了,今天就先来入门泛型编程


文章目录

  • 1.泛型编程
  • 2.函数模版
    • 2.1概念
    • 2.2格式
    • 2.3函数模版的原理
    • 2.4函数模版的实例化
      • 2.4.1隐式实例化
      • 2.4.2显示实例化
    • 2.5 模板参数的匹配原则
  • 3.类模板
    • 3.1概念
    • 3.2格式
    • 3.3类模板的实例化


1.泛型编程

**泛型编程是一种编程范式,旨在编写可以适用于多种数据类型的通用代码。通过泛型编程,我们可以编写一次代码,然后将其应用于不同的数据类型,从而避免重复编写相似的代码 **

之前我们面对多种类型只能这样干:

int Swap(int& a, int& b)
{int temp = a;a = b;b = temp;
}void Swap(double& a, double& b)
{double temp = a;a = b;b = temp;
}int main()
{int a = 1, b = 2;double c = 1.1, d = 2.2;Swap(a, b);Swap(c, d);return 0;
}

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

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

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

现在就轮到泛型编程出场了:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

请添加图片描述


2.函数模版

2.1概念

函数模板是一种允许我们编写通用函数的工具。通过函数模板,我们可以定义一个函数,其中的某些类型可以是通用的,从而使函数能够处理多种数据类型。函数模板使用template关键字定义,并使用一个或多个类型参数来表示通用的类型。

2.2格式

template<typename T1, typename T2,......,typename Tn>//一个或多个
返回值类型 functionName(T parameter1, T parameter2, ...) {// 函数体
}
  • template <typename T>:使用template关键字定义函数模板,并在尖括号中指定一个或多个类型参数.
  • typename是用来定义模板参数关键字,也可以使用class
  • functionName:函数模板的名称。
  • T parameter1, T parameter2, ...:函数模板的参数列表,参数类型为通用的类型T

单模版参数:

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

多模版参数:

template<class T ,class Y>
void print(T& a, Y& b)
{cout << a << " " << b << endl;
}int main()
{int a = 1;double b = 1.1;print(a, b);return 0;
}

请添加图片描述

2.3函数模版的原理

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

当使用函数模板时,编译器会根据传入的参数类型来实例化模板,并生成对应的函数。

还是这段代码:

template<class T>
void Swap(T& a, T& b)
{T temp = a;a = b;b = temp;
}int main()
{int a = 1, b = 2;double c = 1.1, d = 2.2;Swap(a, b);Swap(c, d);return 0;
}

请添加图片描述

转到反汇编看后发现:两处调用函数的地址不一样,这说明不是同一个函数

请添加图片描述

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

2.4函数模版的实例化

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

2.4.1隐式实例化

隐式实例化:让编译器根据实参推演模板参数的实际类型

template<class T>
T add(T& a, T& b)
{return a + b;
}int main()
{int a = 1, b = 2;int ab = add(a, b);double c = 1.1, d = 2.2;double cd = add(c, d);//这样会怎样呢?add(a, c);return 0;
}

add(a, c); 这样调用会怎么样呢 ?

该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型 通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,编译器报错

此时有两种处理方式:

  1. 用户自己来强制转化
template<class T>
T add(const T& a,const  T& b)
{return a + b;
}int main()
{int t1 = add(1, (int)2.2);//自己直接强制转换double t2 = add((double)1, 2.2);return 0;
}
  1. 使用显式实例化

2.4.2显示实例化

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

1.解决类型推测不同问题

template<class T ,class Y>
void print(T& a, Y& b)
{cout << a << " " << b << endl;
}template<class T>
T add(const T& a,const  T& b)
{return a + b;
}int main()
{int a1 = 1;double b1 = 1.1;int a = add<int>(a1, b1);//显示实例化double b = add<double>(a1, b1);print(a, b);return 0;
}

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

  1. 函数模版参数列表里没有通用类型
template<class T>
T* fun1(int n)
{return new T[n];
}int main()
{int* a = fun1<int>(10);//此时必须显示实例化,不然没有办法推测T是什么类型return 0;
}

2.5 模板参数的匹配原则

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

3.类模板

3.1概念

**类模板允许我们创建通用的类,以存储和操作多种数据类型。类模板使用template关键字定义,并可以包含一个或多个类型参数 **

3.2格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{// 类内成员定义
};
template<class T>
class Stack
{
public:Stack(int capacity = 3){cout << "调用了构造函数" << endl;_a = new T[capacity];_top = 0;_capacity = capacity;}~Stack(){cout << "~Stack()" << endl;delete _a;_a = nullptr;_top = -1;_capacity = 0;}
private:int* _a;int _top;int _capacity;
};int main()
{Stack<int> s1;Stack<double> s2;//之前我们都是使用typedef来改变,但是只能存在一个。现在不一样了return 0;
}

3.3类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类而实例化的结果才是真正的类

int main()
{// Stack是类名,Stack<int>和Stack<double>才是类型Stack<int> s1;Stack<double> s2;return 0;
}

好啦,这次的内容就到这里啦。接下来进入stl的学习啦!!感谢大家支持~!

相关文章:

C++初阶:入门泛型编程(函数模板和类模板)

大致介绍了一下C/C内存管理、new与delete后&#xff1a;C初阶&#xff1a;C/C内存管理、new与delete详解 我们接下来终于进入了模版的学习了&#xff0c;今天就先来入门泛型编程 文章目录 1.泛型编程2.函数模版2.1概念2.2格式2.3函数模版的原理2.4函数模版的实例化2.4.1隐式实例…...

【RT-DETR有效改进】CARAFE提高精度的上采样方法(助力细节长点)

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 本文给大家带来的CARAFE(Content-Aware ReAssembly of FEatures)是一种用于增强卷积神经网络特征图的上采样方法。其主要旨在改进传统的上采样方法(就是我们的Upsample)的性能。CARAFE的核心思想是:使用输…...

leetcode 27.移除元素(python版)

需求 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度…...

分布式场景怎么Join

背景 最近在阅读查询优化器的论文&#xff0c;发现System R中对于Join操作的定义一般分为了两种&#xff0c;即嵌套循环、排序-合并联接。 考虑到我的领域是在处理分库分表或者其他的分区模式&#xff0c;这让我开始不由得联想我们怎么在分布式场景应用这个Join逻辑&#xff…...

springboot2.7继承swagger knif4j

maven pom依赖 <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi2-spring-boot-starter</artifactId><version>4.4.0</version></dependency> yml配置 knife4j:enable: trueopenapi:title: …...

C++ 实现单例模式

单例模式 单例模式确保一个类只有一个实例&#xff0c;并提供一个全局访问点。 创建单一实例 怎么让某个类只能创建一个实例&#xff1f; 思路&#xff1a;将类的构造函数私有&#xff0c;然后提供一个静态方法访问对象。调用类内成员函数需要对象&#xff0c;但我们又无法…...

Java多线程--线程安全问题练习题

文章目录 &#xff08;1&#xff09;练习题1&#xff08;2&#xff09;练习题2&#xff08;3&#xff09;练习题3 现在咱们线程一共说了这么几件事情&#xff0c;如下&#xff1a; 具体文章见专栏。 接下来看几个练习题吧。 &#xff08;1&#xff09;练习题1 &#x1f30b;题…...

PHY6252低成本Mesh组网蓝牙芯片

超低成本MESH组网蓝牙芯片PHY6252蓝牙Mesh组网简介 蓝⽛Mesh⽹络使⽤&#xff0c;依赖于低功耗蓝⽛(BLE)。低功耗蓝⽛技术是蓝⽛Mesh使用的无线通信协议栈&#xff0c;蓝牙BR/EDR能够与实现一台设备到另一台设备的连接和通信&#xff0c;建立“一对一”的关系&#xff0c;大多数…...

红外图像中两点校正的增益系数与偏置系数的计算公式推导

增益系数&#xff08;K&#xff09; 根据两个温度下的响应值&#xff0c;可求得各响应单元的响应曲线&#xff08;即斜率&#xff09;&#xff0c;累加所有曲线的斜率求平均斜率值。 平均斜率值与各响应单元的斜率的比值即为该单元的K增益系数。结论&#xff1a;某单元的增益系…...

C++/MFC:在窗体Form(Dialog)中多个编辑框时,在输入时将回车解释为TAB键,将输入焦点移到下一个编辑框的方法

很多时候&#xff0c;为了输入方便&#xff0c;常用的做法&#xff0c;就是将回车键解释为将输入焦点移动到下一个编辑框中。就像是我的VxTerm中的快速连接输入一样&#xff1a; VxTerm是一个国产化替代的SSH工具&#xff0c;可以从本站的资源中免费下载并且免费使用&#xff…...

鸿蒙南向开发——GN快速入门指南

运行GN(Generate Ninja) 运行gn&#xff0c;你只需从命令行运行gn&#xff0c;对于大型项目&#xff0c;GN是与源码一起的。 对于Chromium和基于Chromium的项目&#xff0c;有一个在depot_tools中的脚本&#xff0c;它需要加入到你的PATH环境变量中。该脚本将在包含当前目录的…...

PyCharm常用快捷键和设置

Ctrl Space 基本的代码完成&#xff08;类、方法、属性&#xff09; Ctrl Alt Space 快速导入任意类 Ctrl Shift Enter 语句完成 Ctrl P 参数信息&#xff08;在方法中调用参数&#xff09; Ctrl Q 快速查看文档 F1 外部文档 Shift F1 外部文档…...

Unity - 调节camera物理相机参数(HDRP)

在 “Hierarchy” 右键 -> Volume -> Global Volume new 一个 profile, 设置Mode为Pysical Camera 再点击camera组件&#xff0c;这时候设置 ISO、Shutter Speed、Aperture等参数值还会有效。...

@JsonIgnore的使用及相关问题的解决

目录 1 前言 2 对比及其使用方法 3 遇到的相关问题及解决方法 1 前言 在我们编写的后端项目中&#xff0c;有时候可能需要将某个实体类以JSON格式传送给前端&#xff0c;但是其中可能有部分内容我们并不想传送&#xff0c;这时候我们选择将这部分内容变成Null&#xff0c;这…...

万户 ezOFFICE SendFileCheckTemplateEdit.jsp SQL注入漏洞

0x01 产品简介 万户OA ezoffice是万户网络协同办公产品多年来一直将主要精力致力于中高端市场的一款OA协同办公软件产品,统一的基础管理平台,实现用户数据统一管理、权限统一分配、身份统一认证。统一规划门户网站群和协同办公平台,将外网信息维护、客户服务、互动交流和日…...

自建DNS劫持服务器,纯内网劫持PS5,屏蔽更新,自动hen

背景&#xff1a;目前PS5首次折腾必须要连外网&#xff0c;还要改DNS&#xff0c;除非使用ESP8266/32&#xff0c; 本文的方法是完全不改DNS&#xff0c;不使用ESP8266,不连接外网的情况下自动折腾 能实现什么&#xff1a; 1.折腾全程不连接外网 2.完全自建hen服务器&#xff…...

C语言王道第八周一题

Description 初始化顺序表&#xff08;顺序表中元素为整型&#xff09;&#xff0c;里边的元素是 1,2,3&#xff0c;然后通过 scanf 读取一个元素&#xff08;假如插入的是 6&#xff09;&#xff0c;插入到第 2 个位置&#xff0c;打印输出顺序表&#xff0c;每个 元素占 3 个…...

探索1688店铺所有商品API接口:一键获取海量数据,开启商业智能新篇章

1688店铺所有商品API接口技术详解 一、概述 1688店铺所有商品API接口是阿里巴巴提供的一套应用程序接口&#xff0c;允许第三方开发者获取指定1688店铺下的所有商品信息。通过使用这个接口&#xff0c;开发者可以获取到店铺内所有商品的列表、详情、属性等信息&#xff0c;从…...

使用Win32API实现贪吃蛇小游戏

目录 C语言贪吃蛇项目 基本功能 需要的基础内容 Win32API 介绍 控制台程序部分指令 设置控制台窗口的长宽 设置控制台的名字 控制台在屏幕上的坐标位置结构体COORD 检索指定标准设备的句柄&#xff08;标准输入、标准输出或标准错误&#xff09; 光标信息结构体类型CONSOLE_CUR…...

力扣0114——二叉树展开为链表

[二叉树展开为链表] 难度&#xff1a;中等 题目描述 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

前端中slice和splic的区别

1. slice slice 用于从数组中提取一部分元素&#xff0c;返回一个新的数组。 特点&#xff1a; 不修改原数组&#xff1a;slice 不会改变原数组&#xff0c;而是返回一个新的数组。提取数组的部分&#xff1a;slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...