C++之初阶模板

news2024/11/24 3:05:33

个人主页:救赎小恶魔

欢迎大家来到小恶魔频道

好久不见,甚是想念

今天我们要深入讲述C++内存管理

目录

引言:

模板

  1. 泛型编程

2. 模板函数

2.1函数模板的原理 

2.2模板函数的实例化

2.3函数模板的匹配 

3.类模板

STL

STL 的主要组成部分

STL 的优点

使用 STL 的注意事项


引言:

从这一章开始,我们将正式认识C++的一些模板,这也就是C++比C语言的进阶之处

废话不多说,开始讲解 。

模板

  1. 泛型编程

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++的泛型编程是一种编程范式,它允许程序员编写与类型无关的代码,这些代码可以在多种数据类型上工作,而无需为每个数据类型都编写单独的函数或类。这种特性主要通过模板(templates)来实现。

模板是泛型编程的核心。模板可以是函数模板(function templates)类模板(class templates)。

2. 模板函数

模板函数的定义:

模板函数使用template关键字来声明类型参数。类型参数通常被包含在尖括号<>中,并且用某种标识符(如Ttypename Type等)来表示。

其基本结构是:

template <typename T>
T functionName(T parameter) {
    // 函数实现
}

 下面是一个简单的模板函数的例子,该函数返回两个值的较大者:

template <typename T>  
T max(T a, T b) {  
    return (a > b) ? a : b;  
}

又或者我们写一下上边的交换函数

template <typename T>
void swap(T& a, T& b)
{
	T ret = a;
	a = b;
	b = ret;
}

在这里,typename T 定义了一个类型参数,它在函数模板被实例化时将被具体的类型替换。例如,如果你用 int 类型实例化该模板,编译器将生成一个接受 int 参数并返回 int 类型值的函数,T代表类型

当我们拥有了模板之后,我们就不用再去写其他类型的交换函数了

template <typename T>
void Swap(T& a, T& b)
{
	T ret = a;
	a = b;
	b = ret;
}
int main()
{
	int a, b;
	double c, d;
	a = 1, b = 2;
	c = 3.5, d = 4.5;
	cout << a << endl << b << endl << c << endl << d << endl;
	cout << endl;
	Swap(a, b);
	Swap(c,d);
	cout << a << endl << b << endl << c << endl << d << endl;
	return 0;
}

注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class) 

2.1函数模板的原理 

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

所以这里调用的并不是我们的模版void Swap(T& left, T& right),编译器会根据我们的调用进行类型推导 ,然后调用所推导的模板函数

 这个函数是编译器根据函数模版和需要的类型生成的,这个过程是编译器实现的。

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

2.2模板函数的实例化

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

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

template <typename T>
T Add(T& a, T& b)
{
	return a + b;
}
int main()
{
	int a = 1, b = 2;
	double c = 1.0, d = 3.0;
	cout << Add(a, b) << endl;
	cout << Add(c, d) << endl;
	return 0;
}

 像这种,我们的类型定义为T就是隐式实例化

但如果我们调用

Add(a,d);

这样能实现吗?

该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int或者 double类型而报错,也就是所谓的T不明确

注意:在模板中,编译器一般不会进行类型转换操作

此时有两种处理方式:

  1. 用户自己来强制转化
  2. 使用显式实例化

强制转换:

Add(a, (int)d);
Add((double)a,b);

显示实例化:

template <typename T>
T Add(T a, T b)
{
	return a + b;
}
int main()
{
	int a = 10;
	double b = 20.0;

	// 显式实例化
	Add<int>(a, b);
	return 0;
}

 

2.3函数模板的匹配 

一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数

int Add(int a, int b)
{
	return a + b;
}
template <typename T>
T Add(T a, T b)
{
	return a + b;
}
int main()
{
	//int a = 10;
	//double b = 20.0;
	 显式实例
	Add(1, 2);
    Add<int>(a, b);
    return 0;
}

3.类模板

类模板这玩意挺好用的

我们在学习C语言的时候,需要自己去编写栈,队列等等

而在C++中我们有了类模板就可以直接去调用了

template<class T>
class Stack
{
public:
    Stack(int = 10)
 : _a(new T[capacity])
 , _size(0)
 , _capacity(capacity)
 {}
	void Push(const T& x)
	{}
	~Stack();
private:
	T* _a;
	int _top;
	int _capacity;
};

注意:Stack不是具体的类,是编译器根据被实例化的类型生成具体类的模具

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

Stack<int> s1;
Stack<double> s2;

 Stack类名,Stack<int>才是类型

使用析构函数演示:在类中声明,在类外定义

template <class T>
Stack<T>::~Stack()
{
 if(_a)
 delete[] _a;
 _top = _capacity = 0;
}

STL

C++ 的标准模板库(Standard Template Library, STL)是一个包含了大量通用模板类和函数的库,这些模板类和函数可以用于执行常见的数据结构和算法操作。STL 是 C++ 标准库的重要组成部分,为程序员提供了极大的便利和灵活性。

STL 的主要组成部分

STL 主要由以下几个部分组成:

  1. 容器(Containers)
    • 序列容器:如 vectorlistdequeforward_listarraystring(尽管 string 主要用于处理文本,但它也提供了类似于序列容器的接口)。
    • 关联容器:如 setmultisetmapmultimap,它们基于键值对进行存储,并提供了快速的查找操作。
    • 容器适配器:如 stackqueuepriority_queue,它们是对其他容器的封装,提供了特定的接口和行为。
  2. 迭代器(Iterators)
    • 迭代器是 STL 中的核心概念,它提供了一种访问容器中元素的方式。迭代器类似于指针,但比指针更强大、更安全。STL 中的所有容器都提供了迭代器接口。
  3. 算法(Algorithms)
    • STL 提供了大量的通用算法,如排序、查找、复制、替换等。这些算法可以应用于任何支持迭代器接口的容器。
  4. 函数对象(Functors)
    • 函数对象(也称为仿函数)是重载了 operator() 的类对象,可以像函数一样被调用。在 STL 中,函数对象经常作为算法的参数,用于定义算法的行为。
  5. 内存分配器(Allocators)
    • 内存分配器负责在容器中分配和释放内存。虽然大多数程序员不需要直接使用内存分配器,但 STL 允许你通过自定义分配器来改变容器的内存管理策略。

STL 的优点

  1. 可重用性:STL 提供了大量的通用模板类和函数,可以在不同的项目中重复使用。
  2. 高效性:STL 中的容器和算法都经过了精心设计和优化,可以在大多数情况下提供高效的性能。
  3. 灵活性:STL 的模板特性使得它可以处理多种数据类型,包括基本数据类型、自定义数据类型和指针类型。
  4. 安全性:STL 中的迭代器提供了对容器的安全访问,避免了直接使用指针可能导致的错误。
  5. 可扩展性:你可以通过自定义容器、迭代器、算法和分配器来扩展 STL 的功能。

使用 STL 的注意事项

  1. 理解 STL 的基本概念:在使用 STL 之前,你需要理解其基本概念,如容器、迭代器、算法等。
  2. 注意容器的内存管理:虽然 STL 的容器会自动管理内存,但你需要了解它们的内存管理策略,以避免内存泄漏和其他问题。
  3. 选择合适的容器和算法:在选择容器和算法时,你需要考虑它们的性能、内存使用和易用性等因素。
  4. 避免不必要的复制:在 STL 中,复制操作可能会非常昂贵。因此,你需要避免不必要的复制操作,例如使用引用传递参数而不是值传递。
  5. 注意迭代器失效问题:在 STL 中,迭代器的有效性可能会因为容器的修改而失效。因此,你需要在使用迭代器时格外小心。

累了,今天就到这里了

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

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

相关文章

2024副业指南:年轻人热捧的七大赚钱副业,在家就能做!做得好的月入过万了

副业&#xff0c;听起来就像是在主业之外的“小打小闹”&#xff0c;但你知道吗&#xff1f;很多人通过副业实现了财务自由&#xff0c;甚至有的人副业收入超过了主业&#xff01; 今天&#xff0c;就让我们一起探索那些适合你的副业机会&#xff0c;让你在工作之余也能成为收入…

SpringCloudAlibaba:4.3云原生网关higress的JWT 认证

概述 简介 JWT是一种用于双方之间传递安全信息的简洁的、URL安全的声明规范。 定义了一种简洁的&#xff0c;自包含的方法用于通信双方之间以Json对象的形式安全的传递信息&#xff0c;特别适用于分布式站点的单点登录&#xff08;SSO&#xff09;场景 session认证的缺点 1.安…

内网安全【2】——域防火墙/入站出站规则/不出网隧道上线/组策略对象同步

-隧道技术&#xff1a;解决不出网协议上线的问题(利用出网协议进行封装出网)&#xff08;网络里面有网络防护&#xff0c;防火墙设置让你不能正常访问网络 但有些又能正常访问&#xff0c;利用不同的协议tcp udp 以及连接的方向&#xff1a;正向、反向&#xff09; -代理技术&…

WPF TextBox文本框 输入提示

思路 Grid标签里面创建Label和TextBox&#xff0c;这是一个整体。 TextBox 为空显示 Label OR TextBox 不为空隐藏 Label 。 注意 两个标签的前后顺序。 TextBox文本的背景颜色设置为透明&#xff0c;不然会无法看到 Label 内容。 ElementNametxtStoreName&#xff1a;指定…

【JavaWeb】网上蛋糕项目商城-注册,登录,修改用户信息,提交订单

概念 通过以上多篇文章的讲解&#xff0c;对该项目的功能已经实现了很多&#xff0c;本文将对该项目的用户注册&#xff0c;登录&#xff0c;修改用户信息&#xff0c;以及用户添加至购物车的商品进行提交订单等功能的实现。 注册功能实现 点击head.jsp头部页面的注册按钮&a…

【触摸案例-手势解锁案例-连线到按钮 Objective-C语言】

一、接下来,我们接着来说这个,连线的问题啊, 1.连线的问题啊,也就是说,我现在点击一个按钮, 在移动到下一个按钮的时候,在两个按钮中间,在两个按钮都亮起来的时候呢,我们肯定是让它去画一条线的,那么, 1)首先,如果我现在从第一个按钮,连到第二个按钮,那么,这条…

WSL2中使用USB串口实验

一、主要参考网站: Connect USB devices | Microsoft Learn 连接 USB 设备 | Microsoft Learn 二、安装usbipd-win WSL 本身并不支持连接 USB 设备,因此你需要安装开源 usbipd-win 项目 PS C:\Users\issta> winget install --interactive --exact dorssel.usbipd-win …

【网络编程】HTTPS协议详解

引言 HTTPS是HTTP协议的安全版本&#xff0c;通过使用SSL&#xff08;安全套接层&#xff09;或TLS&#xff08;传输层安全&#xff09;协议加密通信&#xff0c;为数据传输提供了保密性、完整性和身份认证。与传统的HTTP相比&#xff0c;HTTPS能够防止敏感信息被窃取、篡改和…

微信公众号有哪些类型,微信服务号和订阅号有哪些区别

什么是微信公众号&#xff1f; 微信公众号是国内社交媒体平台微信上的公众账号。它们是允许公司发布内容&#xff0c;收集追随者并推广其产品或服务的商业帐户。微信公众号主要有两种类型&#xff1a;订阅账号和服务账号。 微信月活跃用户突破12亿 微信最近达到了平台上的月活…

嵌入式的发展怎么样?

据统计&#xff0c;目前嵌入式人才处于供不应求的状态&#xff0c;对嵌入式工程师的需求达到了全部需求量的 60%至 80%&#xff0c;而且每年还以 20%的速率在增长。因此&#xff0c;学习嵌入式对于大多数人来说&#xff0c;是比较容易找到工作的。 让我再为大家举个例子。近年来…

Pandas进阶

文章目录 第1关&#xff1a;Pandas 分组聚合第2关&#xff1a;Pandas 创建透视表和交叉表 第1关&#xff1a;Pandas 分组聚合 编程要求 使用 Pandas 中的 read_csv() 函数读取 step1/drinks.csv 中的数据&#xff0c;数据的列名如下表所示&#xff0c;请根据 continent 分组并…

ai智能答题助手,这四款软件让知识触手可及!

在数字化时代&#xff0c;知识的获取变得前所未有的便捷。随着人工智能技术的不断发展&#xff0c;AI智能答题助手应运而生&#xff0c;成为了人们学习、工作和生活中的得力助手。今天&#xff0c;就为大家介绍四款备受欢迎的AI智能答题助手软件&#xff0c;让你感受知识的魅力…

Python 进阶(十九):解析命令行参数(argparse 模块)

大家好&#xff0c;我是水滴~~ 当处理命令行参数时&#xff0c;Python 的 argparse 模块是一个强大而灵活的工具。它提供了一个简单且一致的方式来定义命令行参数、选项和子命令&#xff0c;并帮助你解析和验证用户提供的输入。本教程将详细介绍 argparse 模块的使用方法和常见…

5.1 Java全栈开发前端+后端(全栈工程师进阶之路)-服务端框架-MyBatis框架-相信我看这一篇足够

0.软件框架技术简介 软件框架&#xff08;software framework&#xff09;&#xff0c;通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范&#xff0c;也 指为了实现某个软件组件规范时&#xff0c;提供规范所要求之基础功能的软件产品。 框架的功能类似于基础设…

环形链表问题详解

引言 环形链表的题大家都应该做过&#xff0c;如果没有做过可以去某扣上做一下 ,下面有传送门 141. 环形链表 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/linked-list-cycle/submissions/530160081/ 正文 如果在面试的情况下出现了环形链表的题大…

阿里云VOD视频点播流程(1)

一、开通阿里云VOD 视频点播&#xff08;ApsaraVideo VoD&#xff0c;简称VOD&#xff09;是集视频采集、编辑、上传、媒体资源管理、自动化转码处理、视频审核分析、分发加速于一体的一站式音视频点播解决方案。登录阿里云&#xff0c;在产品找到视频点播VOD &#xff0c;点击…

QT4-升级到QT5(1)

1.C报错汇总_nafxcwd.lib error lnk2001-CSDN博客1 1.QT3Support QWidget::setShown 改为QWidget::setVisible 2.头文件 #include<QWidget> 3.部分函数替换

Neo4j+LLM+RAG 环境配置报错处理

开发KGLLMRAG程序时遇到以下报错&#xff0c;记录下处理方案&#xff1a; ValueError: Could not use APOC procedures. Please ensure the APOC plugin is installed in Neo4j and that ‘apoc.meta.data()’ is allowed in Neo4j configuration 这个参考文章&#xff1a;link…

74从零开始学Java之排序算法中的冒泡和选择排序

作者:孙玉昌,昵称【一一哥】,另外【壹壹哥】也是我哦 CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 我们要想成为一个优秀的程序员,其实非常关键的一点就是要锻炼培养自己的编程思维,就好比一个狙击手,要通过大量的射击训练要用大量的子弹喂出来。同样的…

【解决Android Studio】cmake报错找不到vulkan包

1 报错信息 CMake Error at D:/Android/project/cmake/3.10.2.4988404/share/cmake-3.10/Modules/FindPackageHandleStandardArgs.cmake:137 (message): Could NOT find Vulkan (missing: Vulkan_LIBRARY) Call Stack (most recent call first): 2. 错误原因 minSdk版本不对&am…