C++string类的模拟实现以及经验分享

news2024/9/21 5:36:04

文章目录

  • 1. 为什么学习string类?
    • 1.1 C语言中的字符串
    • 1.2 两个面试题
  • 2. string类的实现
    • 构造函数:
    • 拷贝构造函数
    • 赋值运算符重载:
    • 析构函数
    • 流提取运算符重载

1. 为什么学习string类?

1.1 C语言中的字符串

C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些string系列的库函数,例如strcpy、strstr、strcmp、memcpy、memmove等等
,但是这些库函数与字符串是分离开的,不太符合面向对象程序设计的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

1.2 两个面试题

字符串转整形数字
字符串相加
在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。
string类的文档介绍
这里有大量详细有关string类函数的介绍以及使用方法、返回值等等,读者可自行阅读。

2. string类的实现

首先为了不与库中的string类冲突,这里我们要把所有自己写的string类要放在自己的一个命名空间里。这里就拿自己的名字作为命名空间的名字吧。

namespace HB

{
	class string
	{
		public:
		...
		//各种成员函数
		
		private:
		//各种成员变量
        char* _str;
        size_t _capacity;
        size_t _size;

        static const size_t npos = -1;//模仿库里面的npos
	}
}

这里C++专门给int留了绿灯,static的成员变量原本不可以直接在这里赋值,静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明。
对于静态成员变量有不理解的小伙伴可以看这篇文章C++类和对象(下)

构造函数:

这里构造函数参数用的是缺省值,为的是当你定义一个string类对象的时候,不给参数这里能默认提供一个空字符串放到string里,为后续的操作提供方便。

string(const char* str = "")//构造函数
{
      int len = strlen(str);
      _str = new char[len + 1];//开空间

      strcpy(_str, str);//字符串拷贝

      _size = len;
      _capacity = len;
}

拷贝构造函数

一般我们这里传统的写法是自己去根据要拷贝的对象先开一块和它一样大的空间,其次把字符串整体拷贝过去,然后把_size以及_capacity的信息都赋上对应的值。

//传统写法
        //string(const string& s)//拷贝构造函数
        //{
        //    int len = strlen(s._str);
        //    _str = new char[len + 1];

        //    strcpy(_str, s._str);

        //    _size = len;
        //    _capacity = s._capacity;
        //}

大佬研究出来的写法是直接用刚才写好的构造函数去定义好一个temp对象,然后需要我们自己再去针对这个类写一个对象与对象之间的swap函数(最好不要直接用库里面的,因为库里面的swap函数为了适应泛型而进行了相当于3次拷贝构造)
在这里插入图片描述

void swap(string& s)
        {
        //这里我们直接交换成员变量的值即可
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }

但是这里会有一个问题,假如说string s2(s1); 这里的s2的三个成员变量都还是随机值,强行和temp交换之后,temp随着拷贝构造函数的完成编译器要对他进行销毁,这时调用析构函数的时候发现temp对象的_str中的值还是一些随机值,好!那么这里就有野指针的问题了,在VS2013的编译器之下会报错,那么就要去在拷贝构造的初始化列表对于_str进行初始化一下为nullptr,下面析构函数的delete[],对于这个空指针是不会报错的,最后和这个temp对象进行交换即可。

//大佬研究出来的写法
        string(const string& s)//拷贝构造函数
            :_str(nullptr)
            , _size(0)
            , _capacity(0)
        {
            string temp(s._str);
            //this->swap(temp);
            swap(temp);
        }

赋值运算符重载:

传统写法类似于拷贝构造,同样是开空间、赋值等一系列操作,这里不多赘述。

传统写法
        //string& operator=(const string& s)//赋值运算符重载
        //{
        //    if (this != &s)
        //    {
        //        _size = strlen(s._str);
        //        _str = new char[_size + 1];

        //        strcpy(_str, s._str);
        //        _capacity = s._capacity;
        //    }
        //    return *this;
        //}

下面是大佬的写法,既然上面拷贝构造都写好了,那直接就使用拷贝构造来帮我们完成开空间、赋值等操作,然后还是将*this和temp交换,得到的就是我们想要的值了。

        //大佬研究出来的写法
        string& operator=(const string& s)//赋值运算符重载
        {
            if (&s != this)
            {
                string temp(s);//复用拷贝构造
                swap(temp);
            }
            
            return *this;
        }

析构函数

注意上面构造函数new的是一个数组,那么下面delete的时候也要以数组的方式。

 ~string()//析构函数
        {
            delete[] _str;
            _str = nullptr;
            _size = 0;
            _capacity = 0;
        }

流提取运算符重载

老规矩了,像流插入和流提取运算符的重载是不能直接写到成员函数里的,原因:在类里实现的话左操作数是this对象,并且这个this对象只能是类类型,正常我们cout<<d1;但是我们想在类里面实现的话,最后在类里实现完之后使用的时候要d1<<cout,所以说在类里流插入和流提取不能进行重载。这里干脆就只能把它放在类外面,弄成一个全局函数。而且为了能满足链式访问(cout<<s1<<s2<<endl;),我们这里的函数的返回值也得是istream类和ostream类的。

而提取的方法也是有两种,一种是把输入的字符串一个字符一个字符的把它们读到对象s里,而且还用到了标准输入流中的get函数std::istream::get;另外一种方法是为了减少数组频繁扩容,所以找一个数组(大小自己定)把要输入的字符先存放到这个数组中,当这个数组已经满了的时候,或者没有满已经到了输入字符串的末尾了,就把这个数组中的值再整体尾插到string类对象中。
具体实现代码:

istream& operator>>(istream& _cin, string& s)
    {
        方法一:
        //s.clear();
        //char ch = _cin.get();//这种方法如果说输入的字符串比较长的情况下,会进行频繁的扩容,不好
        //while (1)
        //{
        //    if (ch == ' ' || ch == '\n')
        //        break;
        //    s += ch;
        //    ch = _cin.get();
        //}

        //方法二:
        //用一个数组来当作一个缓冲,到达你设置的临界值之后才会向string对象里添加一整个字符串
        s.clear();
        char ch = _cin.get();
        char arr[100] = { '\0' };//初始化为全\0非常重要
        int arrnum = 0;
        while (1)
        {
            if (ch == ' ' || ch == '\n')
                break;
            if (arrnum == 99)
            {
                s += arr;

                arrnum = 0;
            }

            arr[arrnum++] = ch;

            ch = _cin.get();

        }
        arr[arrnum] = '\0';
        s += arr;

        return _cin;
    }

其他成员函数以及完整代码链接
好了今天的分享就到此为止了
最后:如果你觉得对你有用就一键三连吧,哪里有没看懂的地方或者哪里有错误可以在评论区留言欢迎批评指正,作者看到的话会第一时间回复。
end

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

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

相关文章

5款十分小众,却又非常好用的良心软件

今天推荐5款十分小众的软件&#xff0c;知道的人不多&#xff0c;但是每个都是非常非常好用的&#xff0c;有兴趣的小伙伴可以自行搜索下载。 1.杀毒软件——火绒安全软件 首先说一下国产杀软之光&#xff0c;这是一款电脑安全软件&#xff0c;病毒库更新及时&#xff0c;界面…

【文档+视频】Verdi基础教程

目录 前言 1.Verdi 环境配置 2.VCS 产生Verdi 波形 1、tb中加入相应的系统函数 2、makefile中加入相应的选项 3.nTrace 1、如何调用Verdi&#xff1f; 【重点】 2、如何查看包含的设计架构&#xff1f; 3、如何查寻模块实例化的位置&#xff1f;【重点】 4、在nTrace…

Linux网络编程11——简单的web服务器

学习视频链接 02-web大练习的概述_bilibili_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1iJ411S7UA/?p132&spm_id_frompageDriver&vd_source0471cde1c644648fafd07b54e303c905 目录 一、项目展示 二、HTTP 协议基础 2.1 HTTP协议基础。 2.2 请求消息(R…

个人博客系统

目录一、项目简介二、项目开发流程2.1 准备工作2.2 实现Vue层2.2 实现Model层2.4 实现Controller层一、项目简介 基于servlet&#xff0c;采用前后端分离的方式&#xff0c;实现个人博客系统&#xff0c;功能包括&#xff1a;登录、注销、编辑、删除博客、发布博客等. 二、项…

用了10年开源工具,换了Smartbi后,3分钟搞定一份报表

大约在20年前&#xff0c;中国企业开始应用国外BI软件&#xff0c;报表工具可以说是BI 1.0时代的代表产物。在BI软件盛行之初&#xff0c;大部分软件都有开源的&#xff0c;从系统到数据库到各类工具、应用&#xff0c;当时大部分企业使用的BI软件包括报表工具&#xff0c;也都…

外汇天眼:外汇占款是什么意思? 与外汇储备之间的差额是由哪些原因造成的?

外汇占款就是指受资国中央银行回收外汇财产而相对投放的本币。 因为人民币是是非非随意换取代币&#xff0c;外资企业导入后需换取成人民币才可以进到商品流通应用&#xff0c;国家以便外资企业兑换外币要投入很多的资产提升了贷币的需要量&#xff0c;产生了外汇占款。 外汇占…

线程池源码解析 3.excute() 方法

线程池源码解析—excute()方法 execute() execute 方法是线程池的核心方法&#xff0c;所有的方法&#xff0c;包括包装的 FutureTask&#xff0c;都是调用这个方法。 大致流程 这里只是总结了一遍大致的流程&#xff0c;一些细节问题见下面的流程图或者参考源码。 当提交任…

【毕业设计】大数据电商销售预测分析 - python 数据分析

文章目录1 前言2 开始分析2.1 数据特征2.2 各项投入与销售额之间的关系2.3 建立销售额的预测模型3 最后1 前言 &#x1f525; Hi&#xff0c;大家好&#xff0c;这里是丹成学长的毕设系列文章&#xff01; &#x1f525; 对毕设有任何疑问都可以问学长哦! 这两年开始&#x…

Java8新特性 CompletableFuture

Java8新特性 CompletableFuture 什么是CompletableFuture&#xff1f; CompletableFuture类的设计灵感来自于 Google Guava 的 ListenableFuture 类&#xff0c;它实现了 Future 和 CompletionStage 接口并且新增了许多方法&#xff0c;它支持 lambda表达式&#xff0c;通过回…

【IDEA插件】这5款IDEA插件,堪称代码BUG检查神器!

随着业务的发展&#xff0c;系统会越来越庞大&#xff0c;原本简单稳定的功能&#xff0c;可能在不断迭代后复杂度上升&#xff0c;潜在的风险也随之暴露&#xff0c;导致最终服务不稳定&#xff0c;造成业务价值的损失。而为了减少这种情况&#xff0c;其中一种比较好的方式就…

5.盒子阴影(重点)

提示&#xff1a;css3中新增了盒子阴影&#xff0c;我们可以使用box-shadow属性为盒子添加阴影。 1、语法&#xff1a; div{ box-shadow:"h-shadow"或者“v-shadow” } 解释&#xff1a; h-shadow 必须&#xff0c;水平阴影位置&#xff0c;允许负值。 v-shado…

UE4 回合游戏项目 18- 退出战斗

在上一篇&#xff08;UE4 回合游戏项目 17- 进入指定区域触发战斗事件&#xff09;基础上完成击败敌人从而退出战斗的功能。 效果&#xff1a; 步骤&#xff1a; 1.打开“battleScenario”蓝图&#xff0c;添加一个自定义事件&#xff0c;命名为“离开战斗” ​ 2.删除所有…

[附源码]Python计算机毕业设计_社区无接触快递栈

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

手撕二叉搜索树

目录 一、概念 二、常见操作 2.1 查找操作 2.2 插入操作 2.3 删除操作 三、模型应用 3.1 K模型 3.2 KV模型 3.3 代码完整实现 四、 性能分析 一、概念 二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树 它或者是一棵空树&#xff0c;或者是具有以下…

Spring整合Mybatis和Junit小案例(9)

Spring整合Mybatis和Junit环境准备步骤1&#xff1a;准备数据库步骤2&#xff1a;创建项目导入jar包步骤3&#xff1a;根据数据库的表创建模型类步骤4&#xff1a;创建Dao接口步骤5&#xff1a;创建Service接口和实现类步骤6&#xff1a;添加jdbc.properties文件步骤7&#xff…

5种常用格式的数据输出,手把手教你用Pandas实现

导读:任何原始格式的数据载入DataFrame后,都可以使用类似DataFrame.to_csv()的方法输出到相应格式的文件或者目标系统里。本文将介绍一些常用的数据输出目标格式。 01 CSV DataFrame.to_csv方法可以将DataFrame导出为CSV格式的文件,需要传入一个CSV文件名。 df.to_csv(done.…

在 SPRING Boot JPA 中调用带有本机查询中的参数的存储过程

配置pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.…

惊了!10万字的Spark全文!

Hello&#xff0c;大家好&#xff0c;这里是857技术社区&#xff0c;我是社区创始人之一&#xff0c;以后会持续给大家更新大数据各组件的合集内容&#xff0c;路过给个关注吧!!! 今天给大家分享一篇小白易读懂的 Spark万字概念长文&#xff0c;本篇文章追求的是力求精简、通俗…

Linux(基于Centos7)(一)

文章目录一、任务介绍二、基本操作命令三、目录操作命令四、文件操作命令五、查看系统信息六、其他常用命令一、任务介绍 Linux服务器配置与管理&#xff08;基于Centos7.2&#xff09;任务目标&#xff08;一&#xff09; 实施该工单的任务目标如下&#xff1a; 知识目标 1、…

RNA剪接增强免疫检查点抑制疗效

什么是 RNA 剪接&#xff1f;真核生物基因包含一系列外显子和内含子&#xff0c;内含子必须在转录过程中被移除以便成熟的 mRNA 被翻译成蛋白质&#xff0c;RNA 剪接则是这一过程中至关重要的一步。RNA 剪接包含两类剪接事件。组成型剪接 (constitutive splicing): RNA 剪接的一…