当前位置: 首页 > article >正文

2.1-STL库中string类的模拟实现

2.1-STL库中string类的模拟实现

对于C++的类和对象中一些零碎复杂的语法规则,我用模拟实现STL库中常见类和模板总结。

本文中模拟了string中的大部分常用接口,如尾插,中间的插入删除,reserve和resize以及运算符重载,也实现了正向迭代器。

为了能提供可直接运行的代码,接下来的内容在代码块中完成。

#pragma once

#include <iostream>
#include <cstring>
#include <cassert>

namespace my_string
{
    class MyString
    {
    public:
        
        // 迭代器(左闭右开)
        typedef char* iterator;
        typedef const char* const_iterator;

        const_iterator begin() const {
            return _str;
        }
        const_iterator end() const {
            return _str + _size;
        }
        iterator begin() {
            return _str;
        }
        iterator end() {
            return _str + _size;
        }

        // 构造函数
        MyString(const char* str = "") // 全缺省。
            : _size(std::strlen(str))
        {
            _capacity = _size;
            _str = new char[_capacity + 1]; // 有效字符_capacity个,额外添加一个留给\0。
            std::strcpy(_str, str);
        }

        // 析构函数
        ~MyString()
        {
            delete[] _str;
            _str = nullptr;
            _size = _capacity = 0;
        }

        // 拷贝构造——深拷贝
        MyString(const MyString& s)
            : _size(s._size)
            , _capacity(s._capacity)
        {
            _str = new char[s._capacity + 1];
            std::strcpy(_str, s._str);
        }

        // 重载[]
        char& operator[](size_t pos)
        {
            assert(pos < _size);
            return _str[pos];
        }

        const char& operator[](size_t pos) const
        {
            assert(pos < _size);
            return _str[pos];
        }

        // 赋值重载
        MyString& operator=(const MyString& s)
        {
            if (this != &s) // 处理自赋值
            {
                char* temp = new char[s._capacity + 1];
                std::strcpy(temp, s._str);
                delete[] _str;
                _str = temp;
                _capacity = s._capacity;
                _size = s._size;
            }
            return *this;
        }

        // 加上const,使其成为const成员函数。
        const char* c_str() const
        {
            return _str;
        }

        size_t size() const
        {
            return _size;
        }

        // 有关于string比较大小的运算符重载。
        bool operator>(const MyString& s) const {
            return std::strcmp(_str, s._str) > 0;
        }
        bool operator==(const MyString& s) const {
            return std::strcmp(_str, s._str) == 0;
        }
        bool operator<(const MyString& s) const {
            return std::strcmp(_str, s._str) < 0;
        }
        bool operator>=(const MyString& s) const {
            return std::strcmp(_str, s._str) >= 0;
        }
        bool operator<=(const MyString& s) const {
            return std::strcmp(_str, s._str) <= 0;
        }
        bool operator!=(const MyString& s) const {
            return std::strcmp(_str, s._str) != 0;
        }

        // 为了更好的实现插入,先实现reserve。
        void reserve(size_t n) {
            if (n > _capacity) {
                char* tmp = new char[n + 1];
                std::strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
                _capacity = n;
            }
        }

        // 尾插
        void push_back(char ch) {
            if (_size + 1 > _capacity) {
                reserve(_capacity == 0 ? 3 : _capacity * 2);
            }
            _str[_size++] = ch;
            _str[_size] = '\0';
        }

        void append(const char* str) {
            size_t len = std::strlen(str);
            if (_size + len > _capacity) {
                reserve(_size + len);
            }
            std::strcpy(_str + _size, str);
            _size += len;
        }

        // 重载+=,可以直接套用append的运算符重载
        MyString& operator+=(char ch) {
            push_back(ch);
            return *this;
        }
        MyString& operator+=(const char* str) {
            append(str);
            return *this;
        }

        // resize
        void resize(size_t n, char ch = '\0') {
            if (n < _size) {
                // 删除数据
                _size = n;
                _str[n] = '\0';
            }
            else if (n >= _size) {
                reserve(n);
                std::memset(_str + _size, ch, n - _size);
                _size = n;
                _str[_size] = '\0';
            }
        }

        // 中间的插入。
        void insert(size_t pos, char ch) {
            if (pos > _size) return; // 更完善的边界检查
            if (_size + 1 > _capacity) reserve(_capacity == 0 ? 3 : _capacity * 2);
            std::memmove(_str + pos + 1, _str + pos, _size - pos);
            _str[pos] = ch;
            ++_size;
        }

        void insert(size_t pos, const char* str) {
            if (pos > _size) return; // 更完善的边界检查
            size_t len = std::strlen(str);
            if (_size + len > _capacity) reserve(len + _capacity);
            std::memmove(_str + pos + len, _str + pos, _size - pos);
            std::memcpy(_str + pos, str, len);
            _size += len;
        }

        // 中间的删除
        void erase(size_t pos, size_t len = npos) {
            if (pos >= _size) return; // 更完善的边界检查
            if (len == npos || pos + len > _size) {
                _str[pos] = '\0';
                _size = pos;
            }
            else {
                std::memmove(_str + pos, _str + pos + len, _size - pos - len);
                _size -= len;
            }
        }

        // 清空字符串
        void clear() {
            _size = 0;
            _str[0] = '\0';
        }

        // 一些其他的常用接口
        // 代价更低的交换
        void swap(MyString& s) {
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }

        // 寻找
        size_t find(char ch, size_t pos = 0) {
            for (size_t i = pos; i < _size; ++i) {
                if (_str[i] == ch) {
                    return i;
                }
            }
            return npos;
        }

        size_t find(const char* str, size_t pos = 0) {
            char* p = std::strstr(_str + pos, str);
            if (p == nullptr) return npos;
            return p - _str;
        }

    private:
        // 成员变量习惯在开头标记下划线。
        char* _str;
        size_t _size;
        size_t _capacity;

        static const size_t npos;
    };

    const size_t MyString::npos = -1;

    void Print(const MyString& s)
    {
        MyString::const_iterator it = s.begin();
        while (it != s.end()) {
            std::cout << *it;
            it++;
        }
        std::cout << std::endl;
        // const类型的迭代器范围for也可以自行替换,可自行去除注释验证。
        // for (auto e : s) {
        //         std::cout << e << " ";
        //     }
        //     std::cout << std::endl;
    }

    // 流插入重载
    std::ostream& operator<<(std::ostream& out, const MyString& s) {
        for (auto e : s) {
            out << e;
        }
        return out;
    }

    // 流提取重载
    std::istream& operator>>(std::istream& in, MyString& s) {
    s.clear(); // 清空原有的字符串内容
    char ch;
    while (in.get(ch) && ch != ' ' && ch != '\n') {
        s += ch;
    }
    return in;
}

    
    // 下面是一些测试用例。
    void test_string1()
    {
        // 测试构造函数
        MyString s1;
        MyString s2("hello world!");
        std::cout << s1.c_str() << std::endl;
        std::cout << s2.c_str() << std::endl;

        s2[0]++;
        std::cout << s1.c_str() << std::endl;
        std::cout << s2.c_str() << std::endl;
    }

    void test_string2()
    {
        // 验证:如果调用编译器默认拷贝构造,程序会崩溃。
        MyString s1("hello world");
        MyString s2(s1);

        std::cout << s2.c_str() << std::endl;

        MyString s3("iterator");
        // 测试迭代器。
        MyString::iterator it = s3.begin();
        while (it != s3.end()) {
            std::cout << *it << " ";
            it++;
        }
        std::cout << std::endl;
        // 范围for:是迭代器函数的傻瓜替换,故迭代器名字不变,天然可用。
        for (auto ch : s3)
        {
            std::cout << ch << " ";
        }
        std::cout << std::endl;

        // 测试const迭代器。
        MyString s4("const iterator");
        Print(s4);
    }

    void test_string3() {
        MyString s1("hello world");
        MyString s2("hello");

        std::cout << (s1 < s2) << std::endl;
        std::cout << (s1 > s2) << std::endl;
        std::cout << (s1 <= s2) << std::endl;
    }

    void test_string4() {
        MyString s1("hello, world");
        s1.append("123456789");
        Print(s1);

        MyString s2("hello, ");
        s2 += "1";
        Print(s2);

        s2 += "23456789";
        Print(s2);

        // 验证resize
        s2.resize(6);
        Print(s2);

        // 验证insert
        s2.insert(5, 'x');
        s2.insert(5, 'x');
        s2.insert(5, 'x');
        s2.insert(5, 'x');
        Print(s2);
        s2.insert(5, "INSERT");
        Print(s2);

        // 验证erase
        MyString s3("123456789");
        s3.erase(3, 4);// 预期:12389。
        Print(s3);
    }

    void test_string5() {
        MyString s1("1234");
        s1 += '\0';
        s1 += "xxxxxxxx";
        std::cout << s1 << std::endl;
        MyString s2;
        std::cin >> s2;
        std::cout << s2 << std::endl;
    }
}

http://www.kler.cn/a/535978.html

相关文章:

  • 三星OEM版SSD固态硬盘Model码对应关系
  • 【llm对话系统】大模型 Llama 源码分析之并行训练方案
  • 【CPP】CPP经典面试题
  • 云计算部署模式全面解析
  • 导入了fastjson2的依赖,但却无法使用相关API的解决方案
  • 实时波形与频谱分析———傅立叶变换
  • DIY Shell:探秘进程构建与命令解析的核心原理
  • 蓝桥杯小白打卡第二天
  • 【大模型LLM面试合集】大语言模型架构_Transformer架构细节
  • java高级工程师面试题_java高级工程师面试题及答案解析
  • 【原子工具】快速幂 快速乘
  • 基于Flask的商城应用系统的设计与实现
  • vscode中的编辑器、终端、输出、调试控制台(转载)
  • 大数据系统文件格式ORC与Parquet
  • 算法设计-四后问题(C++)
  • 力扣54螺旋矩阵
  • 6 加密技术与认证技术
  • solidity高阶 -- 调用接口合约
  • AWS App2Container
  • C#Halcon差异分类模型
  • 深度学习篇---深度学习中的超参数张量转换模型训练
  • Redis性能优化
  • CSS(三)less一篇搞定
  • Excel交换列位置
  • uniapp商城之用户模块【个人信息】
  • 【如何将pdf颜色模式由rgb转换为cmyk模式】