C++:string类模拟实现

这篇具有很好参考价值的文章主要介绍了C++:string类模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

成员变量

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

C++:string类模拟实现,C++初阶,c++,stl,学习方法,经验分享


构造和析构

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

C++:string类模拟实现,C++初阶,c++,stl,学习方法,经验分享


修改相关

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

C++:string类模拟实现,C++初阶,c++,stl,学习方法,经验分享


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

C++:string类模拟实现,C++初阶,c++,stl,学习方法,经验分享


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

C++:string类模拟实现,C++初阶,c++,stl,学习方法,经验分享


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



文章来源地址https://www.toymoban.com/news/detail-641366.html

完整代码

#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类模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++初阶】模拟实现string的常见操作

    👦个人主页:@Weraphael ✍🏻作者简介:目前学习C++和算法 ✈️专栏:C++航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨ 为了方便管理代码,分两个文件来写: Test.cpp - 测试代码逻辑 string.h - 模拟实现 strin

    2024年02月12日
    浏览(51)
  • 【C++初阶】9. string类的模拟实现

    string类的完整实现放这里啦!快来看看吧 string类的作用就是将字符串类型实现更多功能,运算符重载,增删改查等等操作,所以其成员就包含char*的字符串 在之前的学习过程中,我们了解到类中存在的六个默认函数,其中就包含默认构造函数,那么对于string类是否需要用户自

    2024年02月09日
    浏览(34)
  • 【C++初阶】STL详解(四)vector的模拟实现

    本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C++ 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 注:为了防止与标准库当中的vector产生命名冲突

    2024年02月05日
    浏览(41)
  • 【C++初阶】第八站:string类的模拟实现

    目录 string类的模拟实现 经典的string类问题 浅拷贝 深拷贝 写时拷贝(了解) 构造函数 string的全缺省的构造函数: string的拷贝构造函数 传统写法 现代写法 string的赋值重载函数 传统写法 现代写法 string的无参构造函数: 遍历函数 operator[ ] 迭代器 迭代器的底层实现begin和end:

    2024年04月28日
    浏览(39)
  • 【C++精华铺】10.STL string模拟实现

            STL(标准模板库)是一个C++标准库,其中包括一些通用的算法、容器和函数对象。STL的容器是C++ STL库的重要组成部分,它们提供了一种方便的方式来管理同类型的对象。其中,STLstring是一种常用的字符串类型。         STLstring是一个类,它封装了字符串的操作

    2024年02月09日
    浏览(48)
  • C++ STL学习之【string的模拟实现】

    ✨个人主页: Yohifo 🎉所属专栏: C++修行之路 🎊每篇一句: 图片来源 The key is to keep company only with people who uplift you, whose presence calls forth your best. 关键是只与那些提升你的人在一起,他们的存在唤起了你最好的一面。 string 本质上就是一个专注于存储字符的顺序表,使用起来

    2023年04月09日
    浏览(60)
  • 【C++】STL之string功能及模拟实现

    目录 前沿 一、标准库中的string类 二、string类的常用接口说明  1、string类对象的常见构造  2、string类对象的容量操作  3、string类对象的访问及遍历操作  4、string类对象的修改操作  5、string类非成员函数  6、vs下string结构的说明 三、string类的模拟实现  1、构造函数  2、析

    2024年02月15日
    浏览(44)
  • 【c++】:模拟实现STL模板中的string

        文章目录 前言 一.string的模拟实现 总结   上一篇文章我们详细介绍了STL中的string的一些常用的接口,这一篇文章我们将从底层实现string类,当然我们只是实现一些重要的,经常使用的接口,并且不是完全按照STL中的string去走的。   首先我们为了防止我们写的string类与库

    2024年01月20日
    浏览(52)
  • C++ stl容器string的底层模拟实现

    目录 前言: 1.成员变量 2.构造函数与拷贝构造函数 3.析构函数 4.赋值重载 5.[]重载 6.比较关系重载 7.reserve 8.resize 9.push_back,append和重载+= 10.insert 11.erase 12.find 14.迭代器 15.流插入,流提取重载 16.swap 17.c_str 18.完整代码+测试 总结: 1.成员变量 首先注意的就是_str,不能是const类型

    2024年04月23日
    浏览(42)
  • STL中的string类的模拟实现【C++】

    构造函数设置为缺省参数,若不传入参数,则默认构造为空字符串。字符串的初始大小和容量均设置为传入C字符串的长度(不包括’\\0’) 在模拟实现拷贝构造函数前,我们应该首先了解深浅拷贝: 浅拷贝:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一

    2024年02月15日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包