首页 > 其他分享 >自实现string类

自实现string类

时间:2023-11-27 17:24:52浏览次数:27  
标签:const ms 实现 str another operator MyString string

一. 环境

Linux x86_64,g++ 8.5.0

二. 实现

自实现 string 之前一直想写来着,一直拖着,现在把它完稿。这个版本是比较简单的版本,有一些可能有不同的或者更好的实现方式,后面有机会会加到里面。

打算实现的接口如下

class MyString
{
    friend std::ostream & operator<<(std::ostream & co, const MyString &ms);
    friend std::istream & operator>>(std::istream & ci, MyString &ms);
public:
    MyString(const char * s = nullptr);
    ~MyString();
    MyString(const MyString & another);
    MyString & operator=(const MyString & another);

    MyString operator+(const MyString & another);
    MyString & operator+=(const MyString & another);
    bool operator>(const MyString & another);
    bool operator<(const MyString & another);
    bool operator==(const MyString & another);
    char & operator[](int n);
    char & at(int n);
private:
    char * m_str;
};
  1. 构造函数,参数使用默认参数,默认参数作标记位。不论是否传递实参,申请资源时均以数组形式申请。不传递实参时,申请一个 char 的数组,有传递实参时,以实际的为准。这样,在释放资源时,均可以 delete []m_str 形式释放。
MyString::MyString(const char *str)
{
    if (nullptr == str)
    {
        m_str = new char[1];
        *m_str = '\0';
    }
    else
    {
        m_str = new char[strlen(str)+1];
        strcpy(m_str, str);
    }
}
  1. 拷贝赋值,使用了两种方式。

第一种是基础的写法,先 delete 堆上的空间,再申请新的空间,然后复制内容。需要注意的是,需判断是否是自赋值的情况。

第二种采用了 copy && swap 技术,相对完善一点,前一种方式,在 delete []m_str 后如果程序出现异常,此时其它地方有使用到 m_str 的话就尴尬了,而后一种方式就没有这个问题。

// version1
/*
MyString & MyString::operator=(const MyString &another)
{
    if (this == &another)
    {
        return *this;
    }

    delete []m_str;
    int len = strlen(another.m_str);
    m_str = new char[len+1];
    strcpy(m_str, another.m_str);

    return *this;
}
*/

// version2,采用 copy and swap 技术
MyString & MyString::operator=(const MyString &another)
{
    if (this == &another)
    {
        return *this;
    }

    MyString ms(another);
    std::swap(this->m_str, ms.m_str);

    return *this;
}
  1. 重载 + 运算符,成员函数返回一个临时对象。在申请新的空间后,在使用 strcat() 之前需要初始化,否则可能会出现问题。strcat() 是从末尾为 '\0' 的地方开始拼接的。
MyString MyString::operator+(const MyString &another)
{
    MyString ms;

    int len = strlen(this->m_str) + strlen(another.m_str);
    delete []ms.m_str;
    ms.m_str = new char[len +1]{0};  // 注意初始化
    strcat(strcat(ms.m_str, this->m_str), another.m_str);

    return ms;
}
  1. 重载 += 运算符,返回值类型是引用类型,这样可以连续使用 +=

使用 realloc() 后,在使用 strcat() 连接两个字符串之前,需要将 m_str 后面一部分新扩充的空间进行初始化。

MyString & MyString::operator+=(const MyString &another)
{
    int lenOfSource = strlen(this->m_str);
    int lenOfAnother = strlen(another.m_str);
    this->m_str = (char *)realloc(this->m_str, lenOfSource+lenOfAnother+1);
    memset(this->m_str+lenOfSource, 0, lenOfAnother+1);
    strcat(this->m_str, another.m_str);

    return *this;
}
  1. 重载 > 运算符
bool MyString::operator>(const MyString &another)
{
    return strcmp(this->m_str, another.m_str) > 0;
}

重载 <== 与上面类似,就不重复列举了。

  1. 重载 [] 运算符,这个没啥好说的了。
char & MyString::operator[](int n)
{
    return m_str[n];
}
  1. 成员函数 at()
char & MyString::at(int n)
{
    return m_str[n];
}
  1. 重载输出 << 和 输入 >> 运算符。

在测试成员函数前,可以早点写这两个函数,测试时就方便打印了,不然还需要单独添加一个成员函数返回 m_str 了。

重载运算符,目标形式是:

Mystring ms;
cout << ms; 
cin >> ms;

对于重载,一般会考虑到成员函数重载和全局重载,但是 ostream 类和 istream 类都是系统提供的类,我们不可能在 ostream 类和 istream 类中进行修改,因此只能放弃成员函数重载。此时,只能是全局重载,即全局函数重载了。

考虑到会连续输出(cout << a << b;),因此返回类型是 ostream & 类型,它是经入参而来,入参类型也是 ostream &

std::ostream & operator<<(std::ostream & co, const MyString &ms)
{
    co << ms.m_str;
    return co;
}

输入运算符与输出运算符类似,第二个入参不能是 const 类型,因为需要修改入参 ms。这里处理的相对简单了,栈上申请了1024字节的字符数组用以存储输入的数据,实际上会有不够用的情况。

std::istream & operator>>(std::istream & ci, MyString &ms)
{
    // 简单处理,申请一块固定大小的内存
    char ch[1024];
    ci >> ch;
    delete []ms.m_str;
    ms.m_str = new char[strlen(ch)+1];
    strcpy(ms.m_str, ch);
    return ci;
}

三. 完整代码,可点击链接 mystring ,如有有问题或不到之处,请指出并交流,看到后我会修改。

四. 参考

C++基础与提高 王桂林

标签:const,ms,实现,str,another,operator,MyString,string
From: https://www.cnblogs.com/zhe666/p/17859827.html

相关文章

  • ORA-06502: PL/SQL: 数字或值错误:character string buffer too small
    原因是:DBMS_LOB.SUBSTR(CLOB)报错:超过缓存区长度解决办法:1、将自定义函数中的字符数参数设置为更大的数字(最大32767)。注意,这一设置和Oracle的版本有关系(Oracle10最大为4000,Oracle12可达32767)2、如果是拼接的字段来源是子表,那么就不在原sql中查对应字段,而是在后台JAVA中......
  • Spring Data Redis切换底层Jedis 和 Lettuce实现
    1简介SpringDataRedis是SpringData系列的一部分,它提供了Spring应用程序对Redis的轻松配置和使用。它不仅提供了对Redis操作的高级抽象,还支持Jedis和Lettuce两种连接方式。可通过简单的配置就能连接Redis,并且可以切换Jedis和Lettuce两个连接方式。下面先来看看我们该如何使......
  • 奇瑞捷豹路虎SAP上云,亚马逊云科技为企业云战略的实现保驾护航
     11月23日,“2023第八届IDC中国数字化转型年度盛典”正式开启并揭晓“2023IDC中国未来企业大奖-卓越奖”获奖企业,奇瑞捷豹路虎汽车有限公司(以下简称“奇瑞捷豹路虎”)凭借“基于云原生的智慧化运营平台”项目,继获得“2023IDC未来企业大奖—未来运营领军者优秀奖”后成功荣膺“2023......
  • JavaWeb实现文件上传下载
    JavaWeb中实现文件上传下载使用jar包:smartupload.jar,该包封装了IO流的操作,如果使用Java自带的IO操作会比较繁琐文件上传的基本步骤@WebServlet(urlPatterns="/uploads",name="UploadServlet")//创建文件上传对象SmartUploadsmartupload=newSmartUpload();//初始化上传操......
  • NX二次开发UF_CURVE_add_string_to_ocf_data 函数介绍
    文章作者:里海UF_CURVE_add_string_to_ocf_dataDefinedin:uf_curve.h intUF_CURVE_add_string_to_ocf_data(tag_tstring_tag,intoffset_direction,intnum_offsets,UF_CURVE_ocf_values_p_toffset_distances,UF_CURVE_ocf_data_p_tuf_offset_data)overview概述Addas......
  • 用Python实现网络数据采集的利与弊
    近年来,随着互联网的快速发展,信息爆炸的时代已经到来。在这样的背景下,网络数据采集成为了获取信息和进行分析的重要手段之一。Python作为一种灵活而强大的编程语言,被广泛应用于网络数据采集的实践中。那么,使用Python实现网络数据采集究竟有哪些优点和缺点呢?接下来,我们将对此进行详细......
  • linux系统下php安装mbstring扩展的二种方法
    https://pythonjishu.com/zqqrcvxyfjqmmke/下面是详细讲解“Linux系统下PHP安装mbstring扩展的二种方法”的攻略:方法一:通过源码安装下载PHP源码,并解压缩到指定目录。$tar-zxvfphp-7.4.12.tar.gz//解压PHP源码包进入源码目录,执行configure配置脚本。$cdphp-7.4.12......
  • stat命令的实现-mysate(课上测试)
    提交学习stat(1)的截图推导出实现stat(1)需要的系统调用,并给出实现stat(1)的伪代码需要的系统调用:readdir()、closedir()、fstat()、lstat()、fstatat()伪代码#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/stat.h>#include<dirent.h>......
  • JavaWeb实现简单的文件上传和下载
    一、文件上传1.1文件上传的简单实现前端的标签介绍①需要一个<form>表单标签,请求方式为post请求PS:因为get请求时url有长度限制,而带有文件上传的url一般会超出get请求的长度限制,所以只能用post②<form>标签中需添加enctype属性,属性值必须为multipart/form-dataenctype属性:enc......
  • Flask 实现Token认证机制
    在Flask框架中,实现Token认证机制并不是一件复杂的事情。除了使用官方提供的flask_httpauth模块或者第三方模块flask-jwt,我们还可以考虑自己实现一个简易版的Token认证工具。自定义Token认证机制的本质是生成一个令牌(Token),并在用户每次请求时验证这个令牌的有效性。整个过程可以分......