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; 
};

猜你喜欢

转载自blog.csdn.net/2301_76269963/article/details/132231849