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

【C++初阶】C++入门相关知识(2):输入输出 & 缺省参数 & 函数重载

【C++初阶】C++入门相关知识(2):输入输出 & 缺省参数 & 函数重载

🎈主页传送门:良木生香 🔥个人专栏:《C语言》 《数据结构-初阶》 《程序设计》《鼠鼠的C++学习之路》 🌟人为善,福随未至,祸已远行;人为恶,祸虽未至,福已远离 上期回顾:在上一篇文章中,我们对C++进行了初步的认识,学习了C++的发展历史,第一个C++程序以及命名空间,我们知道,C++的出现就是为了改进和完善C语言的不足,使得程序更加高效,程序员编写起来更加方便快捷,那么本篇文章我们继续往下认识C++的入门相关知识 目录 一、C++的输入&输出 1.1、核心载体:头文件 1.2、核心的IO对象:cin与cout 1.2.1、std::cin 标准输入流 1.

By Ne0inhk
飞算 JavaAI:让 Java 开发效率翻倍的秘密武器 #飞算JavaAl炫技赛 #Java开发

飞算 JavaAI:让 Java 开发效率翻倍的秘密武器 #飞算JavaAl炫技赛 #Java开发

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 * 飞算 JavaAI:让 Java 开发效率翻倍的秘密武器 #飞算JavaAl炫技赛 #Java开发 * 一、引言 * 二、Java 开发现状与挑战剖析 * 2.1 Java 语言的辉煌历史 * 2.2 传统 Java 开发的那些 “坑” * 2.2.1 开发周期:比蜗牛爬还慢 * 2.2.2 人力成本:高得离谱 * 2.2.3 代码质量:参差不齐 * 2.2.

By Ne0inhk
环境搭建 | [入门级]VSCode(Cursor|Trae|Qoder)搭建Java(Springboot3)企业开发环境全流程

环境搭建 | [入门级]VSCode(Cursor|Trae|Qoder)搭建Java(Springboot3)企业开发环境全流程

VSCode搭建Java企业开发环境全流程 在企业级Java开发(如Springboot)中,IDE的选择至关重要。VSCode凭借其轻量、高效、插件生态丰富的特点,逐渐成为许多开发者的首选。本文将详细介绍如何在VSCode中搭建完整的Java企业开发环境,涵盖从基础软件安装到项目调试运行的全流程,适合刚接触VSCode或想迁移Java开发环境的小伙伴。 当前热门的AI IDE(如Cursor、Trae、Qoder)均基于VSCode开发,因此本教程对这类IDE同样适用。 一、准备工作:安装必要软件 在搭建VSCode Java开发环境前,需先安装两个核心工具:JDK和VSCode。 1.1 安装JDK Java开发依赖JDK(Java Development Kit),企业开发建议选择LTS(长期支持)版本,如JDK 11或JDK 17。 1. 安装JDK:运行安装包,按提示完成安装,建议记住安装路径(如Windows下的C:\Program Files\Eclipse Adoptium\jdk-17.

By Ne0inhk
Java 多态

Java 多态

文章目录 * 多态 * 向上转型和向下转型 * 向上转型和重写 * 重写和重载的区别 * 动态绑定和静态绑定 * 用代码来解释什么是多态 * 向下转型 * 多态的优点 * 总结 多态 1. 什么是多态?为什么要使用多态? 简单来说是多种形态,具体来说是去完成某个事情,当不同对象去完成同一件事表现出来的不同结果/状态 打个比方就是同一个人对待不同人表现出来的形态是不同的 2. 多态实现的三个条件: 向上转型和向下转型 向上转型和重写 1. 将子类对象给父类类型的引用 父类类型 对象名 = new 子类类型() 直接赋值的 classAnimal{publicString name;publicint age;publicAnimal(String name,int age){this.name = name;this.age = age;}// 父类中的this是当前对象的引用publicvoideat(){System.out.println(

By Ne0inhk