C++ string 全面指南

C++ string 全面指南

一、模板

1. 函数模板

什么是模板呢模板就是一个模具,只需要往这个模具里倒入不同的材料,就可以获得不同材料的铸件

如果我们要实现一个交换函数呢?这是很容易的事情。

在这里插入图片描述

但是这种交换函数只能实现整型之间的交换,如果我想进行浮点数交换呢,字符型交换呢?是不是就不可以了。

虽然我们可以通过函数重载实现不同的交换函数,但是这样做太浪费时间了,没有意义。毕竟只是改变了交换函数参数的类型,代码不需要变化。所以,这种方法是有缺陷的。

1.代码复用率低

2.可维护性差

所以,有了函数模板,这是实现泛型编程的基础

所谓泛型编程就是编写与类型无关的通用代码,是代码复用的一种手段

在这里插入图片描述

template<typename T>就是定义了一个模板,通过一份代码就可以实现多个要求

这里的typename也可以换成class,这两个的区别会在后面讲解。

这个就叫做函数模板函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本

函数模板的格式template<typename T1, typename T2, ..., typename Tn>

2. 函数模板的原理

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

在这里插入图片描述

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用

3. 函数模板的实例化

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

模板参数实例化分为隐式实例化和显示实例化

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

在这里插入图片描述


在这里插入图片描述

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

在这里插入图片描述

4. 模板参数的匹配原则

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

在这里插入图片描述

.对于非模板函数和同名函数模板,如果其它条件相同,在调用时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生出一个更好匹配的函数,那么将选择模板

在这里插入图片描述

.模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

5. 类模板

.类模板的定义格式

template<classT1,classT2,...,classTn>class 类模板名 {//类内成员定义};
在这里插入图片描述

.类模板的实例化

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

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

二、STL简介

什么是STL呢

STL是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架

那么,我们需要学习STL的哪些部分呢

在这里插入图片描述

主要学习五个部分,空间配置器直接使用即可

三、String

学习string从两方面去学习,一个是了解string类的接口,另一个便是模拟实现string

在这里插入图片描述

string是被 typedef 的真名叫做basic_string<char>,是用来存储字符的

1. constructor

//构造函数,最常用的几个default(1)string();//无参构造copy(2)string(const string& str);//拷贝构造 from c-string(4)string(constchar* s);//字符串构造//不太常用的//从pos位置开始,拷贝str字符串的后len个字符,如果str字符串//太短或者len为npos,那就从pos位置拷贝到str字符串末尾substring(3)string(const string& str, size_t pos, size_t len = npos);//拷贝s指向的字符数组的前n个字符 from sequence(5)string(constchar* s, size_t n);//用n个连续的字符c的拷贝填充stringfill(6)string(size_t n,char c);
在这里插入图片描述
//赋值string(1) string&operator=(const string& str);
在这里插入图片描述

2. Iterators

//如果string对象是一个const类型的,函数返回const_iterator,否则,返回iterator//普通迭代器 iterator begin();//指向字符串的开始 iterator end();//指向字符串的末尾(最后一个字符的下一个位置)//const迭代器 const_iterator begin()const; const_iterator end()const;//反向迭代器//反向迭代器指向string的反向开始位置(也就是string的末尾最后一个字符) reverse_iterator rbegin(); const_reverse_iterator rbegin()const;//指向string的末尾的反向(也就是string的第一个字符的前一个位置) reverse_iterator rend(); const_reverse_iterator rend()const;
在这里插入图片描述

迭代器可以理解成像指针一样,但是迭代器不是指针

3. Capacity

//size和length两个函数的功能是一致的//字符串的字节数 size_t size()const; size_t length()const;//字符串的容量 size_t capacity()const;//清空字符串voidclear();//判断字符串是否为空,length为0返回true,否则,返回falseboolempty()const;//n代表新的字符串的长度,c是用来填充字符串中新的字符空间的字符//如果n小于当前字符串的长度,字符串会缩短至前n个字符,删除第//n个字符之后的所有字符//如果n大于当前字符串的长度,在字符串的末尾插入字符到n个//(c是一个具体的字符,就用c来初始化,否则就用空字符初始化)voidresize(size_t n);voidresize(size_t n,char c);//请求调整字符串的容量,适应将字符串的长度更改为最多n个字符的需求//如果n > str.capacity,容器的容量会增加到n个字符(capacity >= n)//其它情况,缩小字符串的容量是一个非强制性的请求//这个函数不会影响字符串的长度和内容,也就是说即使缩容也不会//比字符串的长度小voidreserve(size_t n =0);//减少字符串的容量去适应它的size//不影响字符串的长度和内容voidshrink_to_fit();

shrink_to_fit通常是异地缩容,因为无法从内存块的中间释放一部分内存

在这里插入图片描述


在这里插入图片描述

这是在vs上运行的结果,是没有缩容的,那么,看一下g++编译器会不会进行缩容呢

在这里插入图片描述

g++下也是没有缩容的。是否缩容,取决于平台

4. Element access

//返回在字符串中pos位置的字符的引用char&operator[](size_t pos);constchar&operator[](size_t pos)const;//与[]的功能一样,这也是为什么string被吐槽的原因,设计了太//多的函数,有些函数功能是一样的,重点掌握[]的使用char&at(size_t pos);constchar&at(size_t pos)const;//返回的是字符串中最后一个字符的引用char&back();constchar&back()const;//返回的是字符串中第一个字符的引用char&front();constchar&front()const;
在这里插入图片描述

5. Modifiers

//在字符串的末尾追加另一个std::string str对象string(1) string&operator+=(const string& str);//字符串的末尾追加C风格的s字符串 c-string(2) string&operator+=(constchar* s);//在字符串的末尾追加单个字符character(3) string&operator+=(char c);
//追加str的拷贝string(1) string&append(const string& str);//从str的subpos位置开始,拿取sublen个字符,追加到string//的对象中,如果str太短或者sublen等于npos,那就取到str的//末尾substring(2) string&append(const string& str, size_t subpos, size_t sublen);//s指向的以空字符结尾的字符序列,追加到string对象中 c-string(3) string&append(constchar* s);//取s指向的字符数组前n个字符,追加到string对象中buffer(4) string&append(constchar* s, size_t n);//n个字符c的拷贝,追加到string对象中fill(5) string&append(size_t n,char c);
//在string对象的末尾添加字符c,string对象的长度增加1voidpush_back(char c);//删除string对象的最后一个字符,string对象的长度减1voidpop_back();
//在pos位置插入str的拷贝string(1) string&insert(size_t pos,const string& str);//从str中的subpos位置开始,取sublen个字符,插入到string//对象中,如果str太短或者sublen等于npos,就从subpos位置//开始一直到str字符串的末尾substring(2) string&insert(size_t pos,const string& str, size_t subpos, size_t sublen);//s指向的以空字符结尾的字符序列,插入到string对象中 c-string(3) string&insert(size_t pos,constchar* s);//s指向的字符数组的前n个字符的拷贝插入到string对象中buffer(4) string&insert(size_t pos,constchar* s, size_t n);//插入字符c的n次拷贝fill(5) string&insert(size_t pos, size_t n,char c);
//从pos位置开始,删除string的len个字符,如果string太短或者len为npos,就删到string的末尾。//注意,该函数默认删除string的所有字符sequence(1) string&erase(size_t pos =0, size_t len = npos);
//从string对象中的pos位置,用str字符串替换掉string对象中的len个字符 string&replace(size_t pos, size_t len,const string& str);
//拷贝str字符串赋值给string对象string(1) string&assign(const string& str);
在这里插入图片描述

insert,erase,replace需慎用,因为string的底层是数组,在插入,删除,数据时,都需要移动数据,这也就意味着时间复杂度为O(N),而替换数据,如果替换的字符串和 len 是相等的,那还是很高效的,但是如果不相等,也需要移动数据,时间复杂度也为O(N)

//得到一个C风格的字符串constchar*c_str()const;//从pos位置开始查找一个string对象string(1) size_t find(const string& str, size_t pos =0)const;//从pos位置开始查找一个字符串 c-string(2) size_t find(constchar* s, size_t pos =0)const;//从pos位置查找s指向的字符数组的前n个字符buffer(3) size_t find(constchar* s, size_t pos, size_t n)const;//从pos位置查找单个字符character(4) size_t find(char c, size_t pos =0)const;//反向查找,与find的功能是一样的,只不过一个从string的开头处查找,一个从string的末尾查找string(1) size_t rfind(const string& str, size_t pos = npos)const; c-string(2) size_t rfind(constchar* s, size_t pos = npos)const;buffer(3) size_t rfind(constchar* s, size_t pos, size_t n)const;character(4) size_t rfind(char c, size_t pos = npos)const;//在字符串中查找第一个出现在指定字符集合中的字符//成功返回第一个匹配字符的位置,失败返回nposstring(1) size_t find_first_of(const string& str, size_t pos =0)const;
//从pos位置开始取len个字符组成一个子串,构造一个新的string对象并返回(或者到字符串的末尾,如果len大于从pos位置开始剩余字符的长度) string substr(size_t pos =0, size_t len = npos)const;
//从pos位置开始,拷贝string对象中的len个字符,存储在s指向的字符数组里 size_t copy(char* s, size_t len, size_t pos =0)const;

npos是一个 size_t 类型,值为 -1,实际值是一个无穷大的数,因为 size_t 是一个无符号整型

在这里插入图片描述
在这里插入图片描述

6. Non-member function

//获取一行字符//is输入流对象,str存储字符的字符串对象,delim提取字符的分割符(1)istream&getline(istream& is, string& str,char delim);(2)istream&getline(istream& is, string& str);
在这里插入图片描述

今天的文章分享到此结束,觉得不错的小伙伴给个一键三连吧。

Read more

GraphQL在Python中的完整实现:从基础到企业级实战

GraphQL在Python中的完整实现:从基础到企业级实战

目录 摘要 1 引言:为什么GraphQL是API设计的未来 1.1 GraphQL的核心价值定位 1.2 GraphQL技术演进路线图 2 GraphQL核心技术原理深度解析 2.1 Schema定义语言与类型系统 2.1.1 Schema定义原则 2.1.2 类型系统架构 2.2 Resolver解析机制深度解析 2.2.1 Resolver执行模型 2.2.2 Resolver执行流程 2.3 Strawberry vs Graphene框架深度对比 2.3.1 架构设计哲学对比 2.3.2 框架选择决策树 3 实战部分:

By Ne0inhk

EasyOCR用法全攻略:Python开源OCR工具快速上手,图文识别零门槛

在日常开发与办公场景中,图文识别(OCR)需求无处不在——比如提取图片中的文字、识别身份证/发票信息、批量处理扫描件等。传统OCR工具要么收费高昂,要么配置复杂,而 EasyOCR 作为Python开源OCR库,凭借“安装简单、支持多语言、识别精度高”的优势,成为入门级OCR开发的首选工具。 本文将从核心特性、环境搭建、基础用法到实战场景,全方位解析EasyOCR的使用技巧,帮你快速实现图文识别功能,无需深厚的计算机视觉知识。 一、为什么选择EasyOCR? 在众多OCR工具中,EasyOCR的核心优势的在于“轻量化+高性价比”,具体体现在: 1. 零门槛上手:API设计简洁,一行代码即可实现文字识别,无需复杂配置; 2. 多语言支持:默认支持80+种语言(中文、英文、日文、韩文等),可通过参数灵活切换; 3. 识别精度高:基于深度学习模型(CNN+

By Ne0inhk

跨平台宏定义的陷阱与优化:从C/C++到HarmonyOS的实战解析

跨平台宏定义的陷阱与优化:从C/C++到HarmonyOS的实战解析 1. 跨平台开发的宏定义挑战 在当今多平台并存的开发环境中,C/C++开发者经常需要面对一个核心问题:如何让同一份代码在不同操作系统上正确编译和运行。宏定义作为C/C++预处理器的重要功能,成为解决平台差异的首选工具,但同时也带来了诸多陷阱。 平台识别宏的混乱现状是开发者面临的首要问题。不同操作系统和编译器定义了各自的一套宏,比如: * Windows平台常见的_WIN32和_WIN64 * Linux平台的__linux__ * macOS的__APPLE__和__MACH__ * HarmonyOS的__harmony__ 更复杂的是,这些宏定义之间存在层级关系和互斥性。例如,在64位Windows系统中,_WIN64和_WIN32会同时被定义,而在32位系统中只有_WIN32被定义。这种复杂性容易导致条件编译的逻辑错误。 宏定义的常见陷阱包括: 1. 宏覆盖问题:不同平台的头文件可能定义了相同名称但含义不同的宏 2. 顺序依赖:宏定义的检测顺序可能影响编译结果 3. 未定义行为:忘

By Ne0inhk

C++【第六篇】 ——— 深入解析多态从语法到底层实现的完整知识体系

目录 多态的条件以及示例代码 一、多态的核心定义:同一行为,不同表现 二、虚函数:实现动态多态的 “开关” 三、虚函数重写(Override):多态的 “前提基础” 四、形成动态多态的两个必要条件 五、代码中的多态执行流程分析 六、总结 虚函数的析构函数 一、析构函数的特殊处理:编译器统一重命名为destructor 二、不加virtual:父子类析构函数构成隐藏关系,导致析构不完整 三、加virtual:父子类析构函数构成重写,满足多态的两个条件 四、代码执行流程分析(加virtual vs 不加virtual) 五、虚析构函数的核心价值 六、总结 抽象类与final和override关键字 一、纯虚函数(Pure Virtual Function) 二、final关键字的两个核心用法

By Ne0inhk