C++模拟实现string类的实例代码

 更新时间:2023年08月13日 14:21:11   作者:派小星233  
这篇文章主要给大家介绍了C++如何模拟实现string类,文章通过代码示例讲解的非常详细,有完整的实现过程,具有一定的参考价值,需要的朋友可以参考下

成员变量

public:
        //类外可能要访问,设计成公有
        static const size_t npos;
 private:
        //指向实际存储字符串的空间
        char* _str;
        //记录容量
        size_t _capacity;
        //记录有效字符,'\0'不算
        size_t _size;
//记得类外定义静态变量
const size_t string::npos = -1;

在这里插入图片描述

构造和析构

string(const char* str = "")
    :_capacity(strlen(str))
    ,_size(_capacity)
{
    _str = new char[_capacity + 1];
    strcpy(_str, str);
}
string(const string& s)
    :_capacity(s._capacity)
    ,_size(s._size)
{
    _str = new char[_capacity + 1];
    strcpy(_str, s._str);
}
~string()
{
    delete[] _str;
    _str = nullptr;
    _size = _capacity = 0;
}

容量相关

1.获取容器大小(_size)和容量(_capacity)

//加const修饰this指针,因为const修饰对象也需要调用这几个接口
size_t size()const
{
    return _size;
}
size_t capacity()const
{
    return _capacity;
}
bool empty()const
{  
    //为空返回true,为假返回false
    return (_size == 0);
}

2.扩容(reserve)

void reserve(size_t n)
{
    //只有n大于容量才进行扩容
    if (n > _capacity)
    {
        //重新开一片空间,拷贝完成后释放原空间
        //修改指针指向,更改容量
        char* tmp = new char[n + 1];
        strcpy(tmp, _str);
        delete[] _str;
        _str = tmp;
        _capacity = n;
    }
}

3.更改容器大小

//设计成半缺省
void resize(size_t n, char c = '\0')
{
    //n > _size,扩容后用c填满容器
    if (n > _size)
    {
        reserve(n);
        for (size_t i = _size; i < _capacity; i++)
        {
            _str[i] = c;
        }
        _str[_capacity] = '\0';
        _size = _capacity;
    }
    else
    {
        //n <= _size的情况,直接把下标n的位置改为'\0',修改_size即可
        _str[n] = '\0';
        _size = n;
    }
}

在这里插入图片描述

修改相关

1.尾插

//尾部插入一个字符
void push_back(char c)
{
    //先判断是否扩容
    if (_size == _capacity)
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    //把原'\0'位置修改为新字符,记得补'\0'
    _str[_size] = c;
    _str[_size + 1] = '\0';
    _size++;
}
//+=复用即可
string& operator+=(char c)
{
    push_back(c);
    return (*this);
}
//尾部插入字符串
void append(const char* str)
{
   size_t len = strlen(str);
   //先判断是否扩容
    if (len + _size > _capacity)
        reserve(len + _size);
    //从原'\0'位置开始拷贝
    strcpy(_str + _size, str);
    //更新_size
    _size += len;
}
string& operator+=(const char* str)
{
    //+=复用即可
    append(str);
    return (*this);
}

在这里插入图片描述

2.指定位置插入

// 在pos位置上插入字符c
string& insert(size_t pos, char c)
 {
     //断言,不然可能越界
     assert(pos <= _size);
     if (_size == _capacity)
         reserve(2 * _capacity);
     //pos位置后字符后移一位
     for (int i = _size; i >= (int)pos; i--)        
         _str[i + 1] = _str[i];
     _str[pos] = c;
     _size++;
     return (*this);
 }
 //在pos位置上插入字符串str
 string& insert(size_t pos, const char* str)
 {
     //断言,不然可能越界
     assert(pos <= _size);
     size_t len = strlen(str);
     if ((_size + len) > _capacity)
         reserve(_size + len);
     for (int i = _size; i >= (int)pos; i--)
     {
         _str[i + len] = _str[i];
     }
     for (int i = 0; i < len; i++)
     {
         _str[pos++] = str[i];
     }
     _size += len;
     return (*this);
 }

在这里插入图片描述

3.指定位置删除

// 删除pos位置上的元素
string& erase(size_t pos, size_t len = npos)
{
    assert(pos <= _size);
    //要删除的字符数大于后面字符,就把pos位置和后面全部删除完
    if (len == npos || pos + len >= _size)
    {
        _size = pos;
        _str[_size] = '\0';
    }
    else
    {
        for (size_t i = pos; i <= pos + _size - len; i++)
        {
            _str[i] = _str[i + len];
        }
        _size -= len;
    }
    return (*this);
}

在这里插入图片描述

4.清空

void clear()
{
     _str[0] = '\0';
     _size = 0;
 }

5.交换两个对象

void swap(string& s)
{
    std::swap(_str, s._str);
    std::swap(_capacity, s._capacity);
    std::swap(_size, s._size);
}

比较相关

//写好< 和 == ,其它复用即可
bool operator<(const string& s)const
{       
    return strcmp(_str, s._str) < 0;
}
bool operator<=(const string& s)const
{
    return (*this) < s || (*this) == s;
}
bool operator>(const string& s)const
{
    return !((*this) <= s);
}
bool operator>=(const string& s)const
{
    return !((*this) < s);
}
bool operator==(const string& s)const
{
    return strcmp(_str, s._str) == 0;
}
bool operator!=(const string& s)const
{
    return !((*this == s));
}

访问相关

char& operator[](size_t index)
{
     assert(index <= _size);
     return _str[index];
}
//函数重载,这个版本专门给const用
 const char& operator[](size_t index)const
{
    assert(index <= _size);
    return _str[index];
}

迭代器相关

//string的迭代器底层是指针
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
    return _str;
}
iterator end()
{
    return (_str + _size);
}
const_iterator begin()const
{
    return _str;
}
const_iterator end()const
{
    return (_str + _size);
}

查找相关

// 查找字符,返回c在string中第一次出现的位置
size_t find(char c, size_t pos = 0) const
{
    assert(pos < _size);
    for (size_t i = pos; i < _size; i++)
    {
        if (_str[i] == c)
            return i;
    }
    return npos;
}
//查找子串,返回子串s在string中第一次出现的位置
size_t find(const char* s, size_t pos = 0) const
{
    //断言,不然可能越界
    assert(pos < _size);
    //直接调用库函数找到子串位置
    const char* p = strstr(_str + pos, s);
    if (p)
        return p - _str;//指针相减得到指针间元素数量,刚好为下标
    else
        return npos;
}

其它成员函数

1.截取子串

string substr(size_t pos, size_t len = npos)
{
    assert(pos < _size);
    string s;
    size_t end = pos + len;
    //如果len大于后面所剩的字符,就把后面全部截取
    if (len == npos || end >= _size)
    {
        len = _size - pos;
        end = _size;
    }
    s.reserve(len);
    for (size_t i = pos; i < end; i++)
    {
        s += _str[i];
    }
    return s;
}

2.取得C格式字符串

const char* c_str()const
{
    return _str;
}

3.赋值

//这里使用传值传参,编译器自行完成拷贝,交换两者即可
string& operator=(string s)
{
     swap(s);
     return (*this);
 }

非成员函数

ostream& operator<<(ostream& _cout, const string& s)
{
    _cout << s.c_str() << endl;
    return _cout;
}
istream& operator>>(istream& _cin, string& s)
{
    s.clear();
    //避免多次扩容,以128为一组进行写入
    char tmp[128] = "";
    int i = 0;
    char ch = '0';
    ch = _cin.get();
    while (ch != ' ' && ch != '\n')
    {
        tmp[i++] = ch;
        if (i == 127)
        {
            tmp[i] = '\0';
            s += tmp;
            i = 0;
        }
        ch = _cin.get();
    }
    if (i != 0)
    {
        tmp[i] = '\0';
        s += tmp;
    }
    return _cin;
}

完整代码

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string.h>
#include<assert.h>
using namespace std;
namespace MyStd
{
    class string
    {
    public:
        typedef char* iterator;
        typedef const char* const_iterator;
        string(const char* str = "")
            :_capacity(strlen(str))
            ,_size(_capacity)
        {
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }
        string(const string& s)
            :_capacity(s._capacity)
            ,_size(s._size)
        {
            _str = new char[_capacity + 1];
            strcpy(_str, s._str);
        }
        string& operator=(string s)
        {
            swap(s);
            return (*this);
        }
        ~string()
        {
            delete[] _str;
            _str = nullptr;
            _size = _capacity = 0;
        }
//
       // iterator
        iterator begin()
        {
            return _str;
        }
        iterator end()
        {
            return (_str + _size);
        }
        const_iterator begin()const
        {
            return _str;
        }
        const_iterator end()const
        {
            return (_str + _size);
        }
        // modify
        //尾部插入一个字符
        void push_back(char c)
        {
            //先判断是否扩容
            if (_size == _capacity)
                reserve(_capacity == 0 ? 4 : _capacity * 2);
            //把原'\0'位置修改为新字符,记得补'\0'
            _str[_size] = c;
            _str[_size + 1] = '\0';
            _size++;
        }
        //+=复用即可
        string& operator+=(char c)
        {
            push_back(c);
            return (*this);
        }
        //尾部插入字符串
        void append(const char* str)
        {
           size_t len = strlen(str);
           //先判断是否扩容
            if (len + _size > _capacity)
                reserve(len + _size);
            //从原'\0'位置开始拷贝
            strcpy(_str + _size, str);
            //更新_size
            _size += len;
        }
        string& operator+=(const char* str)
        {
            //+=复用即可
            append(str);
            return (*this);
        }
        void clear()
        {
            _str[0] = '\0';
            _size = 0;
        }
        void swap(string& s)
        {
            std::swap(_str, s._str);
            std::swap(_capacity, s._capacity);
            std::swap(_size, s._size);
        }
        const char* c_str()const
        {
            return _str;
        }
        /
        // capacity
        //加const修饰this指针,因为const修饰对象也需要调用这几个接口
        size_t size()const
        {
            return _size;
        }
        size_t capacity()const
        {
            return _capacity;
        }
        bool empty()const
        {
            //为空返回true,为假返回false
            return (_size == 0);
        }
        //设计成半缺省
        void resize(size_t n, char c = '\0')
        {
            //n > _size,扩容后用c填满容器
            if (n > _size)
            {
                reserve(n);
                for (size_t i = _size; i < _capacity; i++)
                {
                    _str[i] = c;
                }
                _str[_capacity] = '\0';
                _size = _capacity;
            }
            else
            {
                //n <= _size的情况,直接把下标n的位置改为'\0',修改_size即可
                _str[n] = '\0';
                _size = n;
            }
        }
        void reserve(size_t n)
        {
            //只有n大于容量才进行扩容
            if (n > _capacity)
            {
                //重新开一片空间,拷贝完成后释放原空间
                //修改指针指向,更改容量
                char* tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
                _capacity = n;
            }
        }
        /
        // access
        char& operator[](size_t index)
        {
            assert(index <= _size);
            return _str[index];
        }
        const char& operator[](size_t index)const
        {
            assert(index <= _size);
            return _str[index];
        }
        /
        //relational operators
        //写好< 和 == ,其它复用即可
        bool operator<(const string& s)const
        {       
            return strcmp(_str, s._str) < 0;
        }
        bool operator<=(const string& s)const
        {
            return (*this) < s || (*this) == s;
        }
        bool operator>(const string& s)const
        {
            return !((*this) <= s);
        }
        bool operator>=(const string& s)const
        {
            return !((*this) < s);
        }
        bool operator==(const string& s)const
        {
            return strcmp(_str, s._str) == 0;
        }
        bool operator!=(const string& s)const
        {
            return !((*this == s));
        }
        // 查找字符,返回c在string中第一次出现的位置
        size_t find(char c, size_t pos = 0) const
        {
            assert(pos < _size);
            for (size_t i = pos; i < _size; i++)
            {
                if (_str[i] == c)
                    return i;
            }
            return npos;
        }
        //查找子串,返回子串s在string中第一次出现的位置
        size_t find(const char* s, size_t pos = 0) const
        {
            //断言,不然可能越界
            assert(pos < _size);
            //直接调用库函数找到子串位置
            const char* p = strstr(_str + pos, s);
            if (p)
                return p - _str;//指针相减得到指针间元素数量,刚好为下标
            else
                return npos;
        }
        string substr(size_t pos, size_t len = npos)
        {
            assert(pos < _size);
            string s;
            size_t end = pos + len;
            //如果len大于后面所剩的字符,就把后面全部截取
            if (len == npos || end >= _size)
            {
                len = _size - pos;
                end = _size;
            }
            s.reserve(len);
            for (size_t i = pos; i < end; i++)
            {
                s += _str[i];
            }
            return s;
        }
        // 在pos位置上插入字符c
        string& insert(size_t pos, char c)
        {
            //断言,不然可能越界
            assert(pos <= _size);
            if (_size == _capacity)
                reserve(2 * _capacity);
            //pos位置后字符后移一位
            for (int i = _size; i >= (int)pos; i--)        
                _str[i + 1] = _str[i];
            _str[pos] = c;
            _size++;
            return (*this);
        }
        //在pos位置上插入字符串str
        string& insert(size_t pos, const char* str)
        {
            //断言,不然可能越界
            assert(pos <= _size);
            size_t len = strlen(str);
            if ((_size + len) > _capacity)
                reserve(_size + len);
            for (int i = _size; i >= (int)pos; i--)
            {
                _str[i + len] = _str[i];
            }
            for (int i = 0; i < len; i++)
            {
                _str[pos++] = str[i];
            }
            _size += len;
            return (*this);
        }
        // 删除pos位置上的元素
        string& erase(size_t pos, size_t len = npos)
        {
            assert(pos <= _size);
            //要删除的字符数大于后面字符,就把pos位置和后面全部删除完
            if (len == npos || pos + len >= _size)
            {
                _size = pos;
                _str[_size] = '\0';
            }
            else
            {
                for (size_t i = pos; i <= pos + _size - len; i++)
                {
                    _str[i] = _str[i + len];
                }
                _size -= len;
            }
            return (*this);
        }
    public:
        //类外可能要访问,设计成公用
        static const size_t npos;
    private:
        //指向实际存储字符串的空间
        char* _str;
        //记录容量
        size_t _capacity;
        //记录有效字符,'\0'不算
        size_t _size;
    };
    ostream& operator<<(ostream& _cout, const string& s)
    {
        _cout << s.c_str() << endl;
        return _cout;
    }
    istream& operator>>(istream& _cin, string& s)
    {
        s.clear();
        //避免多次扩容
        char tmp[128] = "";
        int i = 0;
        char ch = '0';
        ch = _cin.get();
        while (ch != ' ' && ch != '\n')
        {
            tmp[i++] = ch;
            if (i == 127)
            {
                tmp[i] = '\0';
                s += tmp;
                i = 0;
            }
            ch = _cin.get();
        }
        if (i != 0)
        {
            tmp[i] = '\0';
            s += tmp;
        }
        return _cin;
    }
    //静态成员在外部定义
    const size_t string::npos = -1; 
};

以上就是C++模拟实现string类的实例代码的详细内容,更多关于C++模拟实现string类的资料请关注脚本之家其它相关文章!

相关文章

  • 你知道C语言中#和##表示的意义吗

    你知道C语言中#和##表示的意义吗

    如标题,这篇文章会讲解C语言中的#和##是啥意思。我相信,大部分朋友应该都没怎么用过,这两个玩意的使用条件也相当苛刻,快跟随小编一起来看看吧
    2023-04-04
  • C++ qt 使用jsoncpp json 读写操作

    C++ qt 使用jsoncpp json 读写操作

    JsonCpp是一个基于C++语言的开源库,用于C++程序的Json数据的读写操作,本文重点给大家介绍C++ qt 使用jsoncpp json 读写操作,感兴趣的朋友跟随小编一起看看吧
    2021-11-11
  • Windows下使用Dev-C++开发基于pthread.h的多线程程序实例

    Windows下使用Dev-C++开发基于pthread.h的多线程程序实例

    下面小编就为大家带来一篇Windows下使用Dev-C++开发基于pthread.h的多线程程序实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • JetBrains CLion永久激活超详细教程(最新激活方法)

    JetBrains CLion永久激活超详细教程(最新激活方法)

    JetBrains Clion 是一款专为 C/C++ 开发所设计的跨平台 IDE,本文适用 JetBrains CLion v2019.3/3.1/3.2/3.3 永久激活,附破解补丁和激活码,可以永久激活 Windows、MAC、Linux 下的 CLion,下面给大家分享JetBrains CLion永久激活超详细教程,感兴趣的朋友一起看看吧
    2023-01-01
  • 使用C语言来画出皮卡丘的教程(附代码)

    使用C语言来画出皮卡丘的教程(附代码)

    在C语言中使用图形库画图需要引入graphics.h库,我们可以通过代码实现画出一个可爱的皮卡丘,将皮卡丘的绘制分为以下部分:耳朵、脸部、眼睛、嘴巴、手臂、腿部、尾巴,下面我们就来学习如何使用C语言编写画皮卡丘的代码
    2024-01-01
  • Qt编写地图实现省市区域图的示例代码

    Qt编写地图实现省市区域图的示例代码

    本文主要介绍了Qt编写地图实现省市区域图的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • C++调用迅雷接口解析XML下载功能(迅雷下载功能)

    C++调用迅雷接口解析XML下载功能(迅雷下载功能)

    这篇文章主要介绍了C++调用迅雷接口,封装解析XML下载的类,功能简单,大家参考使用吧
    2013-11-11
  • C++中stack的pop()函数返回值解析

    C++中stack的pop()函数返回值解析

    这篇文章主要介绍了C++中stack的pop()函数返回值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • C语言 枚举类型(Enum)详解及示例代码

    C语言 枚举类型(Enum)详解及示例代码

    本文主要介绍C语言 枚举类型,这里提供了详细的相关资料及示例代码,以便大家学习参考,有兴趣的小伙伴可以参考下
    2016-08-08
  • c语言 跳台阶问题的解决方法

    c语言 跳台阶问题的解决方法

    本篇文章是对c语言中跳台阶问题的解决方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05

最新评论