C++string类

文章目录

  • 1.string简介
  • 2.string的成员函数
    • [2.1 构造与析构](#2.1 构造与析构)
    • [2.2 访问和修改](#2.2 访问和修改)
      • [2.2.1 string的访问](#2.2.1 string的访问)
        • [2.2.1.1 使用下标访问操作符(中括号)](#2.2.1.1 使用下标访问操作符(中括号))
        • [2.2.1.2 使用迭代器进行访问](#2.2.1.2 使用迭代器进行访问)
        • [2.2.1.3 使用范围for](#2.2.1.3 使用范围for)
        • [2.2.1.4 大小、容量和C-String](#2.2.1.4 大小、容量和C-String)
      • [2.2.2 string的修改](#2.2.2 string的修改)
        • [2.2.2.1 reserve与resize](#2.2.2.1 reserve与resize)
        • [2.2.2.2 添加操作](#2.2.2.2 添加操作)
        • [2.2.2.3 删除操作](#2.2.2.3 删除操作)
    • [2.3 简单的迭代器实现](#2.3 简单的迭代器实现)
    • [2.4 查找功能](#2.4 查找功能)
    • [2.5 关系运算符重载](#2.5 关系运算符重载)
    • [2.6 其它非成员函数](#2.6 其它非成员函数)

1.string简介

< string > 是C++中的自带库,这个库中我们使用最多的就是string类。

为什么会有这个string类?因为C语言中,并没有为字符串单独设置一个内置类型,C语言中的字符串是通过字符数组的方式实现的,因此在C++中,专门引入一个string类。

需要注意的是,我们所使用的string类实质上是一个模板类,即由模板basic_string 实例化出的类再加以重命名后得到的:

下图是我们简单模拟实现的string类中的成员变量

2.string的成员函数

由于一些历史原因,string中的接口设置得相当繁杂,成员函数多,同时一个成员函数又重载为多个函数,所以以下仅介绍string中常用的成员函数

2.1 构造与析构

string中最常用的构造是通过字符串 去初始化以及拷贝构造。 下图是C++11标准下的所有构造函数:

考虑到string类实例化出的对象是会在堆区中申请资源的,因此string类的拷贝构造是通过深拷贝实现的,以下是对string类部分构造的简单实现:


注: 这里拷贝构造涉及到传统写法和现代写法。从本质上讲,无论是传统还是现代写法,都是需要去动态开辟空间 ,只不过传统写法中,开辟空间是自己实现的 ;而在现代写法中,开辟空间是通过复用其它函数实现的。 所以,现代写法在呈现上会更加简洁,除此之外,与传统写法差别不大。

对于析构函数,既然申请了资源,那么析构肯定要我们显式实现,释放动态开辟的空间 即可:

2.2 访问和修改

2.2.1 string的访问

2.2.1.1 使用下标访问操作符(中括号)

string对象可以像C语言中的数组一样进行访问,这本质上是通过运算符重载实现的。

2.2.1.2 使用迭代器进行访问

迭代器 ,即iterator ,是string中实现的一个内部类 ,对于string中的Iterator,我们可以理解为是一个指针,而我们模拟实现string类时,也是将iterator简单实现为指针。

注: 其中迭代器的操作与指针完全相同,但要清楚,iterator本质上不是指针,上述类似的操作是通过运算符重载实现的。

2.2.1.3 使用范围for

范围for是C++中一种极为方便的遍历方式,但范围for的底层 实质上是通过迭代器实现的。

2.2.1.4 大小、容量和C-String

string对象的大小即string中实际存储的有效字符个数 ,string的容量即最多能存储几个有效字符 。需要注意的是,string底层是通过类似顺序表 的方式实现的,所以动态开辟空间时,会比容量多开一个空间用以存储\0.

C++中的string是兼容C的,因为string中实现了一个成员函数 c_str() 用以返回字符串首元素的地址:

2.2.2 string的修改

2.2.2.1 reserve与resize

string类中实现了reserve和resize两个成员函数。

reserve主要是用于扩容的 ,但也可以用于缩容,但是否一定缩容,C++标准是没有规定的,不同的平台下reserve的实现方式不同,缩容也就呈现不同的结果。在vs下,reserve是基本不会缩容的,主要用于扩容。

resize适用于改变有效数据个数的,它可以执行删除以及添加的操作。删除不必多说,添加操作分为两步------首先检查容量是否够存储,如果够,则执行下一步操作,如果不够,则进行扩容;然后,将增加的有效数据处用给定字符填充,如未给定,则使用默认字符c(缺省参数)。

2.2.2.2 添加操作

添加操作中使用最多的无疑是重载的+=运算符,其次则是尾插push_back以及指定位置的插入Insert.

考虑到实际对string对象增添操作的复杂性,上述的成员函数均进行了一定程度的重载以满足不同要求,以下是部分重载的简单实现:

2.2.2.3 删除操作

删除操作最常用的是清空操作clear以及指定位置开始删除指定长度的erase.

不过,这些删除操作都是删除有效数据,即改变size的大小,但不改变capacity,即不会释放动态开辟的空间

erase中会涉及到一个npos .这个是stiring中私有的静态成员变量 ,类型是无符号整型 ,大小是无符号整型的最大值。

当调用erase函数时,未指定长度,长度便是npos,此时显然长度过长,在这种情况下,便会将从指定位置(默认是起始位置)开始的数据(包括指定位置)全部删除;而若主动给定的长度过长,也会执行这样的操作。

2.3 简单的迭代器实现

我们此处使用指针来简单模拟实现string类中的迭代器。

既然将迭代器实现为指针,那么begin()和end()简单返回字符串的起始和结束地址即可。注意,这里的结束地址是\0的地址。

2.4 查找功能

查找功能最常见的是两种:查找第一次出现的某个字符以及查找子串。

查找第一次出现的某个字符简单遍历比较即可,而查找子串则方法比较多,我们这里模拟实现仅简单复用库中中的strstr() 进行查找,这个函数使用的是暴力查找法(BF)。


2.5 关系运算符重载

string对象中的比较与C中strcmp比价的原理相同,这些关系运算符的重载也是通过复用strcmp以及相互复用实现的,比较简单,不作赘述,看下图:

2.6 其它非成员函数

string库中还有一些非成员函数 ,最典型的就是重载在全局的流插入和流提取 ,以及特殊的用于获取输入字符串的函数getline。

流插入实现较为简单,见下图:

此处,着重讲以下流提取的重载以及getline函数。

输入时,读取并存储最简单的方式就是读一个字符,然后便存储这个字符到string对象中。 但是,这样做会有一个弊端,如果读取字符很多的话,会频繁扩容,损耗较大。因此,我们使用一个buffer数组,先暂时存储这些读取的字符,直到满足相应条件的时候,再把buffer数组中的内容一次性全给到string对象中,这样就可以避免频繁扩容,以减小损耗。

流提取getline 都可以用于读取字符串,它们两个最大的区别在于delimiter的不同,即定界符,或者说分隔符的不同。

流提取 默认以空格 或者换行符 作为不同字符串的分隔,也就是说流提取一旦读到空格或者换行符就结束,不会再继续读取。所以,如果想要读取一个内部带空格的字符串,使用流提取是无法实现的。

getline ,顾名思义,是用来读取一行字符串的 。这么说,也不完全正确,准确地说,默认情况下,getline以换行符 作为结束标志,一旦读取到换行符便不再读取。 但是,getline函数是可以指定delimiter的 ,如果你不指定,delimiter就是换行符 ;你若指定,delimiter便是你指定的字符

相关推荐
凡人的AI工具箱4 分钟前
40分钟学 Go 语言高并发:RPC服务开发实战
开发语言·后端·性能优化·rpc·golang
R6bandito_10 分钟前
Qt几何数据类型:QLine类型详解(基础向)
c语言·开发语言·c++·经验分享·qt
杭电码农-NEO13 分钟前
【lua语言基础(四)】IO模型以及补充知识
开发语言·junit·lua
禊月初三15 分钟前
C++面试突破---C/C++基础
c语言·c++·面试
是十一月末19 分钟前
Python语法之正则表达式详解以及re模块中的常用函数
开发语言·python·正则表达式
一只大侠21 分钟前
计算S=1!+2!+3!+…+N!的值:JAVA
java·开发语言
一只大侠23 分钟前
输入一串字符,以“?”结束。统计其中字母个数,数字个数,其它符号个数。:JAVA
java·开发语言·算法
Oneforlove_twoforjob24 分钟前
【Java基础面试题011】什么是Java中的自动装箱和拆箱?
java·开发语言
优雅的落幕41 分钟前
多线程---线程安全(synchronized)
java·开发语言·jvm
小黄编程快乐屋43 分钟前
前端小练习——大雪纷飞(JS没有上限!!!)
开发语言·前端·javascript