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

C++模板编程—学习C++类库的编程基础


课程总目录


文章目录

  • 一、详解函数模板
  • 二、类模板
  • 三、类模板实践:实现向量容器vector
  • 四、理解容器空间配置器allocator的重要性


一、详解函数模板

模板的意义:对类型也可以进行参数化了

// 也可以用template<class T>,但class容易和类混淆,我们都用typename
template<typename T>	// 模板参数列表
bool compare(T a, T b)	// compare是一个函数模板
{cout << "template compare" << endl;return a > b;
}/*
调用点实例化出来的模板函数
bool compare<int>(int a, int b)
{return a > b;
}bool compare<double>(double a, double b)
{return a > b;
}
*/int main()
{// 函数的调用点compare<int>(10, 20);compare<double>(10.5, 20.5);// 函数模板实参推演compare(20, 20); 	 // 还是用的刚才实例化的compare<int>// compare(30, 40.5); // 错误,推演不出来是什么类型// 解决方法一:template<typename T, typename E>,a和b用两个类型,各推各的// 解决方法二:compare<int>(30, 40.5),double强转成int
}

函数模板:不进行编译,因为类型还不知道

模板函数:在函数调用点,编译器用程序员指定的类型,从原模板实例化一份函数代码出来这就叫做模板函数,这是实例化出来真正需要进行编译的函数,因此站在编译器的角度来看,待编译的函数并没有减少,只是我们编写的代码量减少了。
同时,实例化出来的模板函数在.o文件符号表中产生相应的符号,每个函数名的符号只能出现一次

来看看字符串的情况 (模板的特例化)

// 针对compare函数模板,提供const char*类型的特例化版本
template<>	// 要写上
bool compare(const char* a, const char* b)
{cout << "compare<const char*>" << endl;return strcmp(a, b) > 0;
}
// 模板特化不需要在函数名后面加上类型参数
// 即别写成compare<const char*>int main()
{// 推演T为const char*,字符串 > 代表的是比较两个常量的地址,要用strcmp才能比较字符串的字典顺序// 对于某些类型来说,依赖编译器默认实例化的模板代码,代码处理逻辑是错误的// 这时候,就需要我们进行模板的特例化了,这不是编译器提供的,而是程序员提供的compare("aaa", "bbb");compare<const char*>("aaa", "bbb");// 这两种写法都是对的
}

当然,非模板函数(普通函数)优先被调用

//非模板函数 - 普通函数
bool compare(const char* a, const char* b)
{cout << "normal compare" << endl;return strcmp(a, b) > 0;
}int main()
{// 这时候就调用普通函数了,不调用模板函数了compare("aaa", "bbb");// 调用模板函数compare<const char*>("aaa", "bbb");
}

编译器优先把compare处理成函数名字,没有的话,才去找compare模板特例化,如果没有特例化,才进行模板的实例化

分文件编写

模板代码是不能在一个文件中定义,在另一个文件中使用的,否则链接的时候会出现错误

比如在test.cpp中存放模板代码,在main.cpp中声明,这是不可以的,因为声明产生的符号是*UND*,而在test.cpp中只有模板,模板本身是不编译的,没有模板实例化出来的compare<int>等函数,所以不可以

模板代码调用之前,一定要看到模板定义的地方,这样的话,模板才能进行正常的实例化,产生能够被编译器编译的代码。

所以,模板代码都是放在头文件.h当中的,然后在原文件当中直接进行#include包含

模板的非类型参数:

必须是整数类型(整数或者地址/引用都可以)是常量,只能使用,而不能修改

模板不仅可以接受类型参数typename T,还可以接受非类型参数。这些非类型参数可以是整型、指针、引用等。它们在编译时是常量,只能使用,不能修改

示例代码:

template <int N>
class Array {
public:int arr[N];int size() const { return N; }
};int main() {Array<5> myArray; // 创建一个包含5个整数的数组cout << "Array size: " << myArray.size() << endl;return 0;
}
// 使用模板实现冒泡排序
template <typename T, int N>
void bubbleSort(T* arr) {for (int i = N - 1; i >= 1; --i){int flag = 0;for (int j = 1; j <= i; ++j){if (arr[j - 1] > arr[j]){T temp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = temp;flag = 1;}}if (flag == 0)return;}
}int main() {int arr[] = { 64, 34, 25, 12, 22, 11, 90 };const int size = sizeof(arr) / sizeof(arr[0]);// 调用冒泡排序模板函数bubbleSort<int, size>(arr);cout << "排序后的数组: ";for (int i : arr)cout << i << " ";cout << endl;return 0;
}

二、类模板

  • 类模板 → \to 实例化 → \to 模板类
  • 类名称 = 模板名称 + 类型参数列表
  • 为了简化,构造和析构函数不用加<T>,其他出现模板的地方都要加上
  • 类模板可以设置默认类型参数,实例化的时候只用写SeqStack<>就行了
//template<typename T = int> // 类模板可以设置默认类型参数
template<typename T>
class SeqStack
{
public:SeqStack(int size = 10):_pstack(new T[size]), _top(0), _size(size){}~SeqStack(){delete[]_pstack;_pstack = nullptr;}SeqStack(const SeqStack<T>& stack):_top(stack._top), _size(stack._size){_pstack = new T[_size];for (int i = 0; i < _top; i++)_pstack[i] = stack._pstack[i];}SeqStack<T>& operator=(const SeqStack<T>& stack){// 防止自赋值if (this == &stack)return *this;delete[]_pstack;_top = stack._top;_size = stack._size;_pstack = new T[_size];for (int i = 0; i < _top; i++)_pstack[i] = stack._pstack[i];return *this;}void push(const T& val);void pop(){cout << "pop():" << _pstack[_top] << endl;if (empty())return;--_top;}// 之前说过,对于只需要读的方法,最好写成常方法T top() const	// 返回栈顶元素{if (empty())throw "stack is empty";//抛异常也代表函数逻辑结束return _pstack[_top - 1];}bool full() const { return _top == _size; }	// 栈满bool empty() const { return _top == 0; }	// 栈空private:T* _pstack;int _top;int _size;// 扩容void expand(){T* ptmp = new T[_size * 2];for (int i = 0; i < _top; i++)ptmp[i] = _pstack[i];delete[] _pstack;_pstack = ptmp;_size *= 2;}
};// 在类外实现成员方法
// 注意点:1.加类的作用域SeqStack<T>::  2.写template<typename T>
template<typename T>
void SeqStack<T>::push(const T& val)
{cout << "push(const T& val):" << val << endl;if (full())expand();_pstack[++_top] = val;
}

三、类模板实践:实现向量容器vector

template<typename T>
class vector
{
public:vector(int size = 10){_first = new T[size];_last = _first;_end = _first + size;}~vector(){delete[] _first;_first = _last = _end = nullptr;}vector(const vector<T>& vec){int size = vec._end - vec._first;_first = new T[size];int len = vec._last - vec._first;for (int i = 0; i < len; ++i)_first[i] = vec._first[i];_last = _first + len;_end = _first + size;}vector<T>& operator=(const vector<T>& vec){// 防止自赋值if (this == &vec)return *this;// 释放本身指向delete[] _first;// 拷贝int size = vec._end - vec._first;_first = new T[size];int len = vec._last - vec._first;for (int i = 0; i < len; ++i)_first[i] = vec._first[i];_last = _first + len;_end = _first + size;}void push_back(const T& val)	// 向容器末尾添加元素{if (full())expend();*_last++ = val;}void pop_back()		// 从容器末尾删除元素{if (empty())return;--_last;}T back() const		// 返回容器末尾的元素的值{return *(_last - 1);}bool full() const { return _last == _end; }bool empty() const { return _first == _last; }int size() const { return _last - _first; }private:T* _first;	// 指向数组起始位置T* _last;	// 指向数组中有效元素的后继位置T* _end;	// 指向数组空间的后继位置void expend()	// 容器的二倍扩容{int size = _end - _first;T* ptmp = new T[2 * size];for (int i = 0; i < size; ++i)ptmp[i] = _first[i];delete[] _first;_first = ptmp;_last = _first + size;_end = _first + 2 * size;}
};int main()
{vector<int> vec;for (int i = 0; i < 20; ++i)vec.push_back(i);vec.pop_back();	// 弹出19while (!vec.empty()){// 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0cout << vec.back() << " ";vec.pop_back();}cout << endl;return 0;
}

四、理解容器空间配置器allocator的重要性

目前存在的问题:

相关文章:

C++模板编程—学习C++类库的编程基础

课程总目录 文章目录 一、详解函数模板二、类模板三、类模板实践&#xff1a;实现向量容器vector四、理解容器空间配置器allocator的重要性 一、详解函数模板 模板的意义&#xff1a;对类型也可以进行参数化了 // 也可以用template<class T>&#xff0c;但class容易和类…...

[每周一更]-(第99期):MySQL的索引为什么用B+树?

文章目录 B树与B树的基本概念B树&#xff08;Balanced Tree&#xff09;B树&#xff08;B-Plus Tree&#xff09;对比 为什么MySQL选择B树1. **磁盘I/O效率**2. **更稳定的查询性能**3. **更高的空间利用率**4. **并发控制** 其他树结构的比较参考 索引是一种 数据结构&#x…...

详解MySQL的MVCC机制

多版本并发控制&#xff08;MVCC&#xff0c;Multi-Version Concurrency Control&#xff09;是MySQL InnoDB存储引擎用于实现事务隔离和提高并发性能的一种机制。MVCC通过在同一数据的多个版本之间进行管理&#xff0c;允许读写操作并发进行&#xff0c;从而避免了传统锁机制带…...

docker部署skywalking

skywalking版本下载 1&#xff1a;拉取skywalking的oap镜像(可以选择自己的版本&#xff0c;最好与ui&#xff0c;agent版本一致) docker pull apache/skywalking-oap-server:9.5.02&#xff1a;启动oap docker run -d -p 11800:11800 -p 12800:12800 --name sw_oap apache/…...

Mac 使用Docker安装Elasticsearch、Kibana 、ik分词器、head

安装ElasticSearch 通过docker安装es docker pull elasticsearch:7.8.1 在本地创建elasticsearch.yml文件 mkdir /Users/ky/Documents/learn/es/elasticsearch.yml 编辑yml文件内容 http: host: 0.0.0.0 xpack.security.enabled: false xpack.security.enrollment.enabled: t…...

【Webpack4打包机制原理解析】

webpack是一个打包模块化 JavaScript 的工具&#xff0c;在 webpack里一切文件皆模块&#xff0c;通过 Loader 转换文件&#xff0c;通过 Plugin 注入钩子&#xff0c;最后输出由多个模块组合成的文件。webpack专注于构建模块化项目。 # 简单版打包模型步骤 我们先从简单的入手…...

如何提高接口响应速度

在非大数据&#xff08;几万以上记录&#xff09;的情况下&#xff0c;影响接口响应速度的因素中最大的是查询数据库的次数&#xff0c;其次才是数组遍历和简单数据处理&#xff08;如根据已有字段增加新的属性&#xff0c;或计算值&#xff09;。 一般一次数据库查询需要50毫秒…...

项目敏感配置信息加固

概述 引入jasypt做密码等敏感配置信息的加固 项目集成依赖 pom.xml引入jasypt-spring-boot-starter依赖 <dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.…...

HCIA-AI课程大纲

该阶段详细介绍各个机器学习范式方法&#xff0c;涵盖有监督、无监督、半监督、强化学习&#xff0c;以及深度学习算法基础&#xff0c;共计 72 课时。 第一节&#xff1a;华为云 ModelArts 云服务开发环境搭建 - &#xff08;2 课时&#xff09; - 华为云 ModelArts 云服务简…...

keil program algorithm 出错

前段时间 在 调试下载算法时&#xff0c;遇到一个奇怪的问题 就是 加载下载算法后&#xff0c; 下载算法的RAM空间 大小不能修改为 单片机的最大RAM&#xff0c;只能改到最大4KB的空间大小, 再大就报错 刚开始报错 一直不知道原因&#xff0c;走了很多弯路&#xff0c; 到最…...

SITNE24V2BNQ-3/TR一种瞬态电压抑制器,对标PESD1CAN

SITNE24V2BNQ是一种瞬态电压抑制器&#xff0c;设计用于保护两个汽车控制器区域 网络(CAN)母线不受ESD等瞬变造成的损坏。 SITNE24V2BNQ采用SOT-23封装。标准产品不含铅和卤素。 产品参数 方向&#xff1a;双向通道数&#xff1a;2VRWM(V)(Max)&#xff1a;24IPP8/20μS(A)(M…...

Vue3【四】使用Vue2的写法写一个新的组件子组件和根组件

Vue3【四】使用Vue2的写法写一个新的组件 Vue3【四】使用Vue2的写法写一个新的组件 Vue3是向下兼容的&#xff0c;所有可以使用Vue的选项式写法 运行截图 目录结构 文件源码 App.vue <template><div class"app"><h1>你好世界! 我是App根组件<…...

指标体系建设10大坑

在企业经营和运营管理中&#xff0c;指标体系的建设至关重要&#xff0c;它在一定程度上是反映业务的问题状况&#xff0c;影响决策者的决策。但是&#xff0c;在指标体系的建设过程中&#xff0c;常常会存在一些不容忽视的“坑”&#xff0c;今天做个总结&#xff0c;以下为个…...

ubuntu 20.04上docker 使用gpu

要在Docker容器中使用GPU,你需要确保系统上已经安装了正确的NVIDIA驱动程序,并且安装了NVIDIA Container Toolkit。以下是详细的步骤: 1. 安装NVIDIA驱动程序 确保你的系统上已经安装了适当版本的NVIDIA驱动程序。你可以通过运行以下命令来检查驱动程序是否正确安装: nv…...

短剧系统投流版开发,为运营公司投流业务赋能

短剧系统投流版开发是一项复杂的任务&#xff0c;旨在为运营公司的投流业务提供强大的技术支持和赋能。以下是一些关键步骤和考虑因素&#xff0c;以确保短剧系统投流版的成功开发&#xff1a; 一、明确业务需求与目标 首先&#xff0c;需要深入了解运营公司的业务需求、目标…...

入坑必看的几个嵌入式方向热点问题

我们为何要学嵌入式&#xff1f;---需求、薪资、长期发展 嵌入式是成为下一个JAVA吗&#xff1f; 互联网开发和嵌入式开发怎么选&#xff1f; 高薪热门就业方向有哪些&#xff1f; 刚入门&#xff0c;刚毕业&#xff0c;学完没有“工作经验”&#xff0c;能有人要吗&#x…...

电能表如何与智能家居进行有效的融合

随着智能家居技术的不断发展&#xff0c;越来越多的家庭开始使用智能家电、智能照明、智能安防等智能设备&#xff0c;以实现更加便捷、舒适、安全的居住环境。而电能表作为电力系统中不可或缺的一环&#xff0c;不仅承担着计量电能的重要职责&#xff0c;还可以为智能家居系统…...

jmeter多用户登录并退出教程

有时候为了模拟更真实的场景&#xff0c;在项目中需要多用户登录并退出操作&#xff0c;大致参考如下 多用户登录前面已经实现&#xff1a;参考博文 多用户登录并退出jmx文件&#xff1a;百度网盘 提取码&#xff1a;0000 一、多用户退出操作 添加一个setUp线程组&#xff0…...

阿里云ECS实例镜像本地取证

更新时间&#xff1a;2024年03月21日10:09:37 1. 说明 很多非法案件中&#xff0c;服务器是直接搭建在阿里云上的&#xff0c;比如我们在拿到OSSKey之后&#xff08;技术方法、其它方法等&#xff09;&#xff0c;可以将涉案服务器镜像导出&#xff0c;在本地进行取证分析。 …...

不要硬来!班组管理有“巧思”

班组管理&#xff0c;听起来似乎是一个充满“硬气”的词汇&#xff0c;让人联想到严肃、刻板的制度和规矩。然而&#xff0c;在实际操作中&#xff0c;我们却需要运用一些“巧思”&#xff0c;以柔克刚&#xff0c;让班组管理既有力度又不失温度。 在班组管理中&#xff0c;我们…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

[USACO23FEB] Bakery S

题目描述 Bessie 开了一家面包店! 在她的面包店里&#xff0c;Bessie 有一个烤箱&#xff0c;可以在 t C t_C tC​ 的时间内生产一块饼干或在 t M t_M tM​ 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC​,tM​≤109)。由于空间…...

怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)

+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...