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

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

前言:

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

目录

一、string类的构造

二、string类的拷贝构造

三、string类的析构函数

四、string类的运算符重载

1、operator=的传统写法

2、operator=的现代写法

五、代码实例

六、总结


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

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

一、string类的构造

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

cpp 复制代码
private:
 char* _str;

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

cpp 复制代码
//为了区分标准库,我们用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类的拷贝构造

模拟实现的代码如下:

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

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

cpp 复制代码
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的析构函数写法为:

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

四、string类的运算符重载

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

1、operator=的传统写法

cpp 复制代码
    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=的现代写法

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

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

· 传统写法:

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

· 现代写法:

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

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

五、代码实例

cpp 复制代码
//为了区分标准库,我们用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模拟实现的比较重要的部分,其他类函数我们并没有写出来,但难度都不大,感兴趣的老铁可以自己摸索一下或者在网上搜一下它的实现

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

相关推荐
计算机学姐3 分钟前
基于SpringBoot的咖啡店管理系统【个性化推荐+数据可视化统计+配送信息】
java·vue.js·spring boot·后端·mysql·信息可视化·tomcat
My的梦想已实现13 分钟前
关于JAVA Springboot集成支付后打包JAR之后报安全错误的处理
java·spring boot·jar
ooseabiscuit28 分钟前
SpringBoot3整合FastJSON2如何配置configureMessageConverters
java
苏宸啊30 分钟前
rbtree封装map和set
c++
·醉挽清风·35 分钟前
学习笔记—Linux—信号阻塞&信号捕捉
linux·笔记·学习
ok_hahaha37 分钟前
java从头开始-黑马点评-Redission
java·开发语言
无巧不成书021838 分钟前
Java面向对象零基础实战:从Employee类吃透自定义类核心,掌握封装精髓
java·开发语言·java入门·面向对象·自定义类·employee类·java核心技术
小江的记录本42 分钟前
【注解】常见 Java 注解系统性知识体系总结(附《全方位对比表》+ 思维导图)
java·前端·spring boot·后端·spring·mybatis·web
跃上青空1 小时前
Java如何优雅的使用fastjson2进行枚举序列化/反序列化,欢迎探讨
java·开发语言
汉克老师1 小时前
GESP2025年6月认证C++三级( 第一部分选择题(1-8))
c++·二进制·原码·补码·gesp三级·gesp3级·八进制、