C++初阶学习第七弹——探索STL奥秘(二)——string的模拟实现

news2024/11/25 22:58:07

标准库中的string:C++初阶学习第六弹——string(1)——标准库中的string类-CSDN博客

前言:

在前面我们已经学习了如何使用标准库中的string类,但作为一个合格的程序员,我们不仅要会用,还要知道如何实现string中的类函数等内容,今天我们就来讲解一下string的模拟实现

目录

一、string类的构造

二、string类的拷贝构造

三、string类的析构函数

四、string类的运算符重载

1、operator=的传统写法

2、operator=的现代写法

五、代码实例

六、总结


string的模拟实现中最重要的就是string类的构造、拷贝构造、赋值运算符重载以及析构函数

接下来我们就围绕这些重点进行学习

一、string类的构造

首先我们要清楚string类在底层实际上就是一个字符指针和许多类函数,所以它的类成员变量就是:

private:
 char* _str;

我们先把模拟构造给出来再来讲解:

//为了区分标准库,我们用String
class String
{
public:
    String(const char* str = "")
    {
        if (str == nullptr)
        {
            assert(false);
            return;
        }
        _str = new char[strlen(str) + 1];
        strcpy(_str, str);
    }
    void String_print()
    {
        cout << _str << endl;
    }
private:
    char* _str;
};
int main()
{
    String s1("abc");
    s1.String_print();
    return 0;
}

运行结果:

相信一定有细心的朋友已经注意到我们在给参数时并没有给任何东西,原因如下:

还有一点需要注意的是:我们在赋值时是创建一个新空间来储存,并不是直接赋值,这就涉及深拷贝的问题了,在下面我们讲拷贝构造的时候能更清晰的体现出来

二、string类的拷贝构造

模拟实现的代码如下:

    String(const String& s)
        : _str(new char[strlen(s._str) + 1])
    {
        strcpy(_str, s._str);
    }

在这里我们主要来讲解一下深拷贝和浅拷贝的问题,我们放在一个完整的代码实例:

class String
{
public:
    String(const char* str = "")
    {
        if (str == nullptr)
        {
            assert(false);
            return;
        }
        _str = new char[strlen(str) + 1];
        strcpy(_str, str);
    }
    String(const String& s)
        : _str(new char[strlen(s._str) + 1])
    {
        strcpy(_str, s._str);
    }
    void String_print()
    {
        cout << _str << endl;
    }
private:
    char* _str;
};
int main()
{
    String s1("abc");
    s1.String_print();
    String s2(s1);
    s2.String_print();
    return 0;
}

运行结果:

错误示范:

三、string类的析构函数

由于string类对象不管以哪个方式创建时,都需要用new来开辟空间,所以string的析构函数写法为:

    ~String()
    {
        if (_str)     //检查一下_str是否为空,如果为空就不用再释放空间了
        {
            delete[] _str;
            _str = nullptr;
        }
    }

四、string类的运算符重载

string类的运算符重载整体来说没啥难度,在这里我们也不做过多讲解,重点来讲解一下operator=的两种写法

1、operator=的传统写法

    String& operator=(const String& s)
    {
        if (s._str != _str)
        {
            char* ptr = new char[strlen(s._str) + 1];    //+1是因为要多开辟一个空间存放\0
            strcpy(ptr, s._str);
            delete _str;                              //清空_str中可能有的数据
            _str = ptr;
        }
        return *this;
    }

2、operator=的现代写法

String& operator=(String s)
{
    swap(_str, s._str);   //swap函数算法库中存在,所以可以直接使用
    return *this;
}

单从篇幅上来比较,现代写法要比传统写法精简的多,那么它们两个究竟是如何实现它们的功能的呢?我们看下面的分析:

· 传统写法:

传统写法函数的参数是后值的引用,我们通过创建一个新的字符指针,并开辟空间接受后值,再把这个新创建的指针的地址传给我们的对象,从而实现了operator=的功能

· 现代写法:

现代写法则聪明的使用了算法库中的swap函数,从而让函数达到一个很精简的效果,该函数的参数是后值的临时拷贝,本来就是深拷贝,所以通过swap交换即可

传统写法和现代写法的过程比较:

五、代码实例

//为了区分标准库,我们用String
class String
{
public:
    String(const char* str = "")
    {
        if (str == nullptr)
        {
            assert(false);
            return;
        }
        _str = new char[strlen(str) + 1];
        strcpy(_str, str);
    }
    String(const String& s)
        : _str(new char[strlen(s._str) + 1])
    {
        strcpy(_str, s._str);
    }
    //现代写法
    String& operator=(String s)
    {
        swap(_str, s._str);
        return *this;
    }
    传统写法
    //String& operator=(const String& s)
    //{
    //    if (s._str != _str)
    //    {
    //        char* ptr = new char[strlen(s._str) + 1];    //+1是因为要多开辟一个空间存放\0
    //        strcpy(ptr, s._str);
    //        delete _str;                              //清空_str中可能有的数据
    //        _str = ptr;
    //    }
    //    return *this;
    //}
    void String_print()
    {
        cout << _str << endl;
    }
    ~String()
    {
        if (_str)     //检查一下_str是否为空,如果为空就不用再释放空间了
        {
            delete[] _str;
            _str = nullptr;
        }
    }
private:
    char* _str;
};
int main()
{
    String s1("abc");
    s1.String_print();
    String s2(s1);
    s2.String_print();
    String s3 = s2;
    s3.String_print();
    return 0;
}

运行结果:

六、总结

以上就是string模拟实现的比较重要的部分,其他类函数我们并没有写出来,但难度都不大,感兴趣的老铁可以自己摸索一下或者在网上搜一下它的实现

感谢各位大佬观看,创作不易,还请一键三连!!!

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

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

相关文章

Jmeter 性能-阶梯负载最终请求数

1、设置阶梯加压线程组请求参数 说明&#xff1a; 每隔2秒钟&#xff0c;会在1秒内启动5个线程 每次线程加载之后都会运行2s然后开始下一次线程加载 最终会加载50个线程并持续运行30s 50个线程持续运行30s后&#xff0c;会每隔2秒钟停止5个线程&#xff0c;剩余的线程继续负…

猫头虎分享已解决Error || ERROR: Failed building wheel for XXX

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

2005-2022年各省共同富裕指数数据(含原始数据+结果)

2005-2022年各省共同富裕指数数据&#xff08;含原始数据结果&#xff09; 1、时间&#xff1a;2005-2022年 2、来源&#xff1a;统计年鉴、各省年鉴 3、范围&#xff1a;31省 4、指标&#xff1a;年份、行政区划代码、地区、人均可支配收入_元、人均消费支出_元、恩格尔系…

Oracle: 一个用户多个表空间处理

1.场景描述 今天工作中&#xff0c;同事说建了一个用户&#xff0c;往里面导入数据时提示表空间不存在&#xff0c;建了表空间后&#xff0c;部分仍然导不进去。期望帮忙创建表空间&#xff0c;并指定默认表空间&#xff0c;成功将数据导入。 &#xff08;1&#xff09;创建好的…

WIFI模块的AT指令联网数据交互--第十天

1.1.蓝牙&#xff0c;ESP-01s&#xff0c;Zigbee, NB-Iot等通信模块都是基于AT指令的设计 初始配置和验证 ESP-01s出厂波特率正常是115200, 注意&#xff1a;AT指令&#xff0c;控制类都要加回车&#xff0c;数据传输时不加回车 1.2.上电后&#xff0c;通过串口输出一串系统…

【联合索引】最左匹配原则是什么?

什么是联合索引 联合索引&#xff08;Composite Index&#xff09;是一种索引类型&#xff0c;它由多个列组成。 MySQL的联合索引&#xff08;也称为复合索引&#xff09;是建立在多个字段上的索引。这种索引类型允许数据库在查询时同时考虑多个列的值&#xff0c;从而提高查询…

物联网五层架构分析

物联网五层架构分析 随着科技的迅速发展&#xff0c;物联网&#xff08;IoT&#xff09;作为日常生活中不可或缺的一部分&#xff0c;已融入人们的生活和工作中。物联网五层架构&#xff0c;包括感知层、网络层、数据层、应用层和业务层&#xff0c;扮演着关键的角色。 感知层 …

通往糊涂之路 The road to serfdom

最近被推送了一本书&#xff0c;哈耶克的............ 试一试&#xff0c;看看能不能看懂&#xff0c;也许是通往糊涂之路。

IMDB的电影评论数据pytorh使用lstm

使用lstm对IMDB的电影评论数据进行情感分析&#xff08;pytorch代码&#xff09; 接下来让我们看看如何使用pytorch实现一个基于长短时记忆网络的情感分析模型。在飞桨中&#xff0c;不同深度学习模型的训练过程基本一致&#xff0c;流程如下&#xff1a; 数据处理&#xff1…

鸿蒙开发接口Ability框架:【AbilityMonitor】

AbilityMonitor AbilityMonitor模块提供匹配满足指定条件的受监视能力对象的方法的能力&#xff0c;最近匹配的能力对象将保存在AbilityMonitor对象中。 说明&#xff1a; 本模块首批接口从API version 9 开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起…

C#之partial关键字

在C#中&#xff0c;partial关键字用于声明一个类、结构体、接口或方法的分部定义。这意味着可以将一个类或其他类型的定义分成多个部分&#xff0c;这些部分可以在同一个命名空间或程序集中的多个源文件中进行定义。当编译器编译这些部分时&#xff0c;会将它们合并成一个单独的…

LeetCode/NowCoder-链表经典算法OJ练习2

最好的&#xff0c;不一定是最合适的&#xff1b;最合适的&#xff0c;才是真正最好的。&#x1f493;&#x1f493;&#x1f493; 目录 说在前面 题目一&#xff1a;分割链表 题目二&#xff1a;环形链表的约瑟夫问题 SUMUP结尾 说在前面 dear朋友们大家好&#xff01;&…

【计算机网络】Socket网络编程

&#x1f4bb;文章目录 &#x1f4c4;前言Socket编程基础概念工作原理 Socket API介绍socket函数绑定、监听函数accept、connect接受/发送函数 Socket API的应用Socket类与其派生类的设计服务器与客户端的设计使用 &#x1f4d3;总结 &#x1f4c4;前言 现今我们的日常生活当中…

【爬虫基础1.1课】——requests模块上

目录索引 requests模块的作用&#xff1a;实例引入&#xff1a; 特殊情况&#xff1a;锦囊1&#xff1a;锦囊2: 这一个栏目&#xff0c;我会给出我从零开始学习爬虫的全过程。感兴趣的小伙伴可以关注一波&#xff0c;用于复习和新学都是不错的选择。 那么废话不多说&#xff0c…

sqli-labs 第十七关

目录 找注入点&#xff1a; 源码分析&#xff1a; 测试&#xff1a; 奇怪现象&#xff1a; &#xff08;1&#xff09;&#xff1a;当我们输入的密码为字符进行注入时。 &#xff08;2&#xff09;&#xff1a;当我们输入的密码为整数时。 产生原因&#xff1a; 解决方法…

孙宇晨对话大公网:香港Web3政策友好环境示范意义重大

日前,全球知名华文媒体大公网发布《湾区web3大有可为》重磅系列报道。报道通过对中国香港与大湾区其他城市Web3政策、行业创新和生态建设等方面的梳理,以及对行业领袖和重要行业机构的走访,全面展现了在大湾区一体化发展的背景下,Web3等数字经济模式在该地区的长远发展潜力。 …

基于Idea搭建Android开发环境

文章目录 下载SDK ManagerAndroid SDK Platform-toolsAndroid SDK Build-toolsAndroid SDKAndroid SDK Extras IDEA设置创建TestApp导入Android Studio创建的项目 下载SDK Manager SDK Manager是Google提供的&#xff0c;专门用于下载/管理&#xff0c;安卓开发中需要用到的工…

【MYSQL】一颗B+树可以保存多少条数据

引言 事万物都有自己的单元体系&#xff0c;若干个小单体组成一个个大的个体。就像拼乐高一样&#xff0c;可以自由组合。所以说&#xff0c;如果能熟悉最小单元&#xff0c;就意味着我们抓住了事物的本事&#xff0c;再复杂的问题也会迎刃而解。 存储单元 存储器范围比较大…

鸿蒙ArkUI开发:常用布局【交叉轴】

交叉轴 垂直于主轴方向的轴线。Row容器交叉轴为纵向&#xff0c;Column容器交叉轴为横向。通过alignItems属性设置子元素在交叉轴&#xff08;排列方向的垂直方向&#xff09;上的对齐方式alignSelf属性用于控制单个子元素在容器交叉轴上的对齐方式&#xff0c;其优先级高于al…

鸿蒙内核源码分析(内核态锁篇) | 如何实现快锁Futex(下)

本篇为快锁下篇&#xff0c;说清楚快锁在内核态的实现&#xff0c;解答以下问题&#xff0c;它们在上篇的末尾被提出来。 鸿蒙内核进程池默认上限是64个&#xff0c;除去两个内核进程外&#xff0c;剩下的都归属用户进程&#xff0c;理论上用户进程可以创建很多快锁&#xff0…