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

初始C++模板

1.泛型编程

1.1什么事泛型编程

在学习C语言时,我们时常会有这样的烦恼:

在针对每一种不同的类型变量进行函数传参或者是运算处理时,我们总是编写不同的函数或者是进行不同的处理,才能达到目的,这时,我们就会想到,有没有什么操作能够让我们只写一种函数就能堆所有的百年来那个类型都进行处理,在C++中,就实现了泛型编程。

我们先来看看下面的代码:

这是C语言的交换函数:

void swapi(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
void swapd(double* x, double* y)
{double tmp = *x;*x = *y;*y = tmp;
}
int main()
{int i = 12;int j = 20;printf("整形, 交换前:i:%d, j:%d\n", i, j);swapi(&i, &j);printf("整形, 交换后:i:%d, j:%d\n", i, j);double in = 12.5;double jn = 32.6;printf("双精度浮点型, 交换前:i:%lf, j:%lf\n", in, jn);swapd(&in, &jn);printf("双精度浮点型, 交换后:i:%lf, j:%lf\n", in, jn);return 0;
}

 从上面的代码我们可以看出,在C语言中我们进行,相同的操作,但由于受限于变量的类类型,我们还是需要进行许多操作,这不由得让我们觉得过于冗余。

但是反泛型编程就能够很好的解决这样的问题:

我们来及看下面的代码:


using namespace std;template<class T>
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}
int main()
{int i = 12;int j = 20;printf("整形, 交换前:i:%d, j:%d\n", i, j);Swap(i, j);printf("整形, 交换后:i:%d, j:%d\n", i, j);double in = 12.5;double jn = 32.6;printf("双精度浮点型, 交换前:i:%lf, j:%lf\n", in, jn);Swap(in, jn);printf("双精度浮点型, 交换后:i:%lf, j:%lf\n", in, jn);return 0;
}

通过反省编程,我们就轻松的实现了,各类型的数据交换,避免了C语言中的一些无法避免的问题,是程序更加的见解,可读性也变得更高!

接下来,我们就来正式的了解一下什么是泛型编程。

2. 泛型模板

我们可以想象一下,在一个制作工艺中,我们通常可以通过相同的模板来实现将不同的类型的材料,塑造吃呢公同样的形状,在这里,我们就需要用到一种模具来实现这样的操作。

如果C++中,也存在这样的模板的话,通过在模板上填充不同的材料(类型变量),来获取不同才来哦的构建(即生成相应的代码),那将会节省许多的头发。巧的就是,前人早已将树种好,我们现在只需要再次乘凉就好。

所以综上:泛型编程就是:编写与类型无关代码,是代码复用的手段。模板是反省编程的基础。

3.函数模板

3.1函数模板的概念 

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

3.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)

3.3函数模板实现的原理

函数 模板是一个蓝图,他本省并不是函数,是编译器使用方式产生具体类型的函工具。所以其实魔板就是将我们本应该重复做的事情交给了编译器来做,这样可以可以提高效率。

在编译器的编译阶段,对于函数模板,编译器需要根据传入的参数来推演出生成对应函数的类型,将T确定为double类型,然后产生一份专门处理double类型的代码 ,对于其他的类型也都是这样的。

3.4函数模板的实例化

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

隐式实例化和显示实例化

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

template<class T>
T Add(const T& left, const T& right)
{
return left + right;
} i
nt 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;
}

 2.显示实例化:在函数的使用时,在函数名的后面<>中指定模板参数的实际类型

i
nt main(void)
{
int a = 10;
double b = 20.0;
// 显式实例化
Add<int>(a, b);
return 0;
}

如果类型不匹配,编译器会尝试进行隐式类型转化,如果无法进行正确的转化,编译器就会报错。

3.5模板参数的匹配原则

1.一个非模板函数可以和一个同名的函数一起存在,而且这个函数在进行调用时。会有先调用已经存在的类型的函数,同时,模板函数还是可以经过实例化生成这个函数。

// 专门处理int的加法函数
int Add(int left, int right)
{
return left + right;
} /
/ 通用加法函数
template<class T>
T Add(T left, T right)
{
return left + right;
} v
oid Test()
{
Add(1, 2); // 与非模板函数匹配,编译器不需要特化
Add<int>(1, 2); // 调用编译器特化的Add版本
}

2.对于非模板函数和对应同名的函数模板, 如果其他条件相同,在调用时会有优先调用非模板函数而不会从该模板中产生一个实例。如果模板可以产生一个更好的实力函数,那么,编译器还是会考虑从模板重中生成。

// 专门处理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函数
}

3.模板函数不允许自动类型转换,但是普通函数可以进行这样的操作!

4.类模板

4.1类模板的定义方式 

template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
#include<iostream>
using namespace std;
// 类模版
template<typename T>
class Stack
{ p
ublic:
Stack(size_t capacity = 4)
{
_array = new T[capacity];
_capacity = capacity;
_size = 0;
}void Push(const T& data);
private:
T* _array;
size_t _capacity;
size_t _size;
};
// 模版不建议声明和定义分离到两个文件.h 和.cpp会出现链接错误,具体原因后面会讲
template<class T>
void Stack<T>::Push(const T& data)
{
// 扩容
_array[_size] = data;
++_size;
} 
int main()
{
Stack<int> st1; // int
Stack<double> st2; // double
return 0;
}

 4.2类模板的实例化

类模板的实例化与函数的模板实例化有所不同,类模板实例化需要在类模板名字后面跟<>,然后就爱那个实力化的类型放在<>中即可,类模板的名字不是真正的类,而是实例化后的结果才是真正的类!!!


/ Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double

好,今天的内容就到这里,咱们下期再见,拜拜!! 

相关文章:

初始C++模板

1.泛型编程 1.1什么事泛型编程 在学习C语言时&#xff0c;我们时常会有这样的烦恼&#xff1a; 在针对每一种不同的类型变量进行函数传参或者是运算处理时&#xff0c;我们总是编写不同的函数或者是进行不同的处理&#xff0c;才能达到目的&#xff0c;这时&#xff0c;我们…...

建投数据自主研发相关系统获得欧拉操作系统及华为鲲鹏技术认证书

近日&#xff0c;经欧拉生态创新中心和华为技术有限公司测评&#xff0c;建投数据自主研发的投资项目管理系统、全面风险管理信息系统、商业不动产业务系统&#xff0c;完成了基于欧拉操作系统openEuler 22.03、华为鲲鹏Kunpeng 920&#xff08;Taisha 200&#xff09;的兼容性…...

node启动websocket保持后台一直运行

在 Node.js 中启动一个 WebSocket 服务器并使其在后台持续运行&#xff0c;你可以使用几种方法。下面是一种常见的方法&#xff0c;通过创建一个简单的 WebSocket 服务器并使用 node 命令直接运行它&#xff0c;同时确保它在后台运行。 1. 创建 WebSocket 服务器 首先&#x…...

CSS画出三角形的做法

引言&#xff1a; 在网页中&#xff0c;会有三角形的出现&#xff0c;我们脑海里会有很多想法&#xff0c;如何去实现他们&#xff0c;我来提供一种比较好玩的做法。 方法&#xff1a; 我们实现一个三角形&#xff0c;当然可以使用精灵图、或者iconfont的做法&#xff0c;这…...

web开发(1)-基础

这是对b站课程的总结&#xff0c;后续可能会继续更 01 前后端分离介绍_哔哩哔哩_bilibili01 前后端分离介绍是Web应用开发-后端基础-基于Springboot框架的第1集视频&#xff0c;该合集共计29集&#xff0c;视频收藏或关注UP主&#xff0c;及时了解更多相关视频内容。https://w…...

python程序操作Windows系统中的软件如word等(是否可以成功操作待验证)

一、python打开word软件 在 Python 中可以使用python-docx库来操作 Word 文档&#xff0c;但如果你的需求是直接打开 Word 软件&#xff0c;你可以使用os模块和subprocess模块来实现。以下是示例代码&#xff1a; import os import subprocessdef open_word():word_path rC:…...

人工智能发展历程

发展历程 人工智能的发展可以追溯到20世纪30年代&#xff0c;当时数理逻辑的形式化和智能可计算思想开始构建计算与智能的关联概念。1943年&#xff0c;美国神经科学家麦卡洛克和逻辑学家皮茨共同研制成功了世界上首个人工神经网络模型——MP模型&#xff0c;这为现代人工智能…...

Flutter路由

路由作为一种页面切换的能力&#xff0c;非常重要。Flutter 中路由管理有几个重要的点。 Navigator 1.0&#xff1a;Flutter 早期路由系统&#xff0c;侧重于移动端 &#xff0c;命令式编程风格&#xff0c;使用 Navigator.push() 和 Navigator.pop() 等方法来管理路由栈。 N…...

css预处理器less

CSS预处理器Less教程 CSS预处理器是一种扩展CSS功能的工具&#xff0c;它允许开发者使用变量、嵌套规则、混合&#xff08;Mixins&#xff09;、函数等高级特性&#xff0c;使CSS代码更加灵活、易于维护和扩展。Less是其中一种流行的CSS预处理器&#xff0c;它使用JavaScript编…...

WEB服务器——Tomcat

服务器是可以使用java完成编写&#xff0c;是可以接受页面发送的请求和响应数据给前端浏览器的&#xff0c;而在开发中真正用到的Web服务器&#xff0c;我们不会自己写的&#xff0c;都是使用目前比较流行的web服务器。 如&#xff1a;Tomcat 1. 简介 Tomcat 是一个开源的轻量…...

C++ STL(3)list

文章目录 一、list 详解1、内存管理2、常用操作3、迭代器erase()删除list中的元素 前言&#xff1a; C 标准模板库&#xff08;STL&#xff09;中的 list 容器是一种双向链表数据结构&#xff0c;它允许在常数时间内进行插入和删除操作&#xff0c;而无需重新分配整个容器或移动…...

Ubuntu下安装Zookeeper集群

Zookeeper集群是一个开源的分布式协调服务系统&#xff0c;它由Apache软件基金会维护&#xff0c;旨在为分布式应用提供一致性和可靠性的服务。 在Zookeeper集群中&#xff0c;服务器可以扮演三种角色——领导者&#xff08;Leader&#xff09;、跟随者&#xff08;Follower&a…...

模版and初识vector

一、引言 在C语言中&#xff0c;不论是数组&#xff0c;还是结构体定义的数组&#xff0c;功能都比较欠缺&#xff0c;不是单纯的添加几个变量就能够解决的。缺少增删查改的功能&#xff0c;为了解决这个问题&#xff0c;C决定填上C语言这个坑&#xff0c;但是填过坑的人都知道…...

网站开发基础:HTML、CSS

前端开发主要使用的技术如 HTML、CSS 和 JavaScript 等。 简单制作一个网页 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>柒毓同学网站的首页</title><style>.c1{border: solid 1px g…...

IP协议讲解

IP协议 IP协议的本质&#xff1a;提供一种能力&#xff0c;将数据跨网络从A主机传输到B主机 4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4. 4位头部长度(header length): IP头部的长度是多少个32bit, 也就是 length * 4 的字节数. 4bit表示最大 的数字是15, 因…...

SpringMVC4-SpringMVC获取请求参数

目录 通过ServletAPI获取&#xff08;不常用&#xff09; 通过控制器方法的形参获取请求参数 RequestParam RequestHeader CookieValue 通过POJO获取请求参数 解决获取请求参数的乱码问题 test_param.html&#xff1a; <!DOCTYPE html> <html lang"en&qu…...

【C++】C++基础

目录 一. C关键字(C98) 二、C的第一个程序 三、命名空间 3.1.namespace的价值 3.2.namespace的定义 3.2.命名空间使用 总结&#xff1a;在项目当中第一、第二种方法搭配使用&#xff0c;第三种冲突风险非常大&#xff0c;仅适合练习使用。 四、C输入&输出 五、缺省…...

自动化运维工具 Ansible

Ansible 基础 Ansible 介绍 Ansible 是一个自动化运维工具&#xff0c;基于Python开发&#xff0c;集合了众多运维工具&#xff08;puppet、cfengine、chef、 func、fabric&#xff09;的优点&#xff0c;实现了批量系统配置、批量程序部署、批量运行命令等功能。 Ansible 的…...

深度学习:GAN图像生成

GAN的诞生背景 诞生&#xff1a; 2014年由Ian Goodfellow提出 创新性&#xff1a; 无监督学习&#xff1a;GAN 提供了一种新的方法来进行无监督学习&#xff0c;即不需要对训练数据进行标注就可以学习到数据的潜在分布。对抗训练&#xff1a;通过引入对抗机制&#xff0c;G…...

django基于python的房价分析可视化系统的设计与开发 h1y0i

目录 项目介绍技术栈具体实现截图Scrapy爬虫框架关键技术和使用的工具环境等的说明解决的思路开发流程爬虫核心代码展示系统设计论文书写大纲详细视频演示源码获取 项目介绍 大数据分析是现下比较热门的词汇&#xff0c;通过分析之后可以得到更多深入且有价值的信息。现实的科…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

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

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

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...