string模拟实现

string模拟实现

整体代码

#pragma once
#include

namespace hqj
{
 class string
 {
    public:
        friend ostream& operator<<(ostream& _cout, const hqj::string& s);

        friend istream& operator>>(istream& _cin, hqj::string& s);

        string(const char* str = "")//构造函数
            :_size(strlen(str))
            , _capacity(_size)
        {
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }
        
        string(const string& s)//拷贝构造函数
            :_capacity(0)
            , _size(0)
            , _str(nullptr)
        {
            string tmp(s._str);//这里不能传s,原因是要调用构造函数而不是拷贝构造函数
            swap(tmp);
        }

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

        void reserve(size_t n)
        {
            if (n > _capacity)
            {
                char* tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;

                _capacity = n;
            }
        }

        void push_back(char c)//尾插一个字符
        {
            if (_size >= _capacity)//不要去改变_capacity
            {
               
                reserve(_capacity == 0 ? 4 : _capacity * 2);
            }

            _str[_size] = c;
            _size++;
            _str[_size] = '\0';
        }

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

            strcpy(_str + _size, str);
            _size += len;
        }

        //+=运算符重载
        string& operator+=(char c)
        {
            push_back(c);
            return *this;
        }

        string& operator+=(const char* str)
        {
            append(str);
            return *this;
        }

      
        size_t capacity()const
        {
            return _capacity;
        }

        bool empty()const
        {
            return _size == 0;
        }
    

        void clear()//清空string对象
        {
            _str[0] = '\0';
            _size = 0;
        }

        void swap(string& s)//string的交换函数,是现代写法的基础(包工头写法
        {
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }

        const size_t size()const//string有效数据个数
        {
            return _size;
        }

        //[]运算符重载
        char& operator[](size_t index)
        {
            assert(index < _size);
            return _str[index];
        }

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

        //迭代器部分
        typedef char* iterator;

        iterator begin()
        {
            return _str;
        }

        iterator end()
        {
            return _str + _size;
        }

        const iterator begin() const
        {
            return _str;
        }

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

        string& operator=(const string& s)
        {
            string tmp(s);
            swap(tmp);
            return *this;
        }

        //提供私有成员_str
        const char* c_str()const
        {
            return _str;
        }

        // 返回c在String中第一次出现的位置

        size_t find(char c, size_t pos = 0) const
        {
            assert(pos < _size);
            for (int 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);
            char* tmp = strstr(_str + pos, s);
            if (tmp == nullptr)
            {
                return npos;
            }
            return find(*tmp);
        }


        // 在pos位置上插入字符c/字符串str,并返回该字符的位置

        string& insert(size_t pos, char c)
        {
            assert(pos <= _size);//pos=size相当于尾插
            if (_size >= _capacity)//不要去改变_capacity
            {
                reserve(_capacity == 0 ? 4 : _capacity * 2);
            }
            size_t end = _size + 1;
            while (end != pos)
            {
                _str[end] = _str[end-1];
                end--;
            }
            _str[pos] = c;
            _size++;
            return *this;
        }

        string& insert(size_t pos, const char* str)
        {
            assert(pos <= _size);
            size_t len = strlen(str);
            if (_size+len >= _capacity)//不要去改变_capacity
            {
                reserve(_size+len);
            }
            size_t end_new = _capacity;
            size_t end_old = _size;
            while (end_old > pos)
            {
                _str[end_new] = _str[end_old];
                end_old--;
                end_new--;
            }
            _str[end_new] = _str[pos];
            for (int i = 0; i < len; i++)
            {
                _str[pos++] = str[i];
            }
            _size+=len;
            return *this;
        }

        // 删除pos位置上的元素,并返回该元素的下一个位置
        void erase(size_t pos, size_t len = npos)
        {
            assert(pos < _size);

            if (len == npos || pos + len >= _size)
            {
                _str[pos] = '\0';
                _size = pos;
            }
            else
            {
                size_t begin = pos + len;
                while (begin <= _size)
                {
                    _str[begin - len] = _str[begin];
                    ++begin;
                }
                _size -= len;
            }
        }


        void resize(size_t n, char c = '\0')
        {
            size_t len = strlen(_str);
            if (n > _capacity)
            {
                reserve(n);
                for (int i = len + 1; i < _capacity; i++)
                {
                    (*this) += c;
                }
            }
            else
            {
                _str[n] = '\0';
            }
            _size = n;
        }

        bool operator<(const string& s)
        {
            if (strcmp(_str, s._str) < 0)
            {
                return true;
            }
            return false;
        }

        bool operator<=(const string& s)
        {
            if ((*this) < s || (*this) == s)
            {
                return true;
            }
            return false;
        }

        bool operator>(const string& s)
        {
            return !(*this <= s);
        }

        bool operator>=(const string& s)
        {
            return !(*this < s);
        }

        bool operator==(const string& s)
        {
            if (strcmp(_str, s._str) == 0)
            {
                return true;
            }
            return false;
        }

        bool operator!=(const string& s)
        {
            return!((*this) == s);
        }


    private:
        char* _str;
        size_t _size;
        size_t _capacity;
    public:
        const static size_t npos;
 };

    const size_t string::npos = -1;
    //流插入流提取的运算符重载
    ostream& operator<<(ostream& out, const hqj::string& s)
    {
        for (int i = 0; i < s.size(); i++)
        {
            out << s._str[i];
        }
        return out;
    }
   
 /*   istream& operator>>(istream& in, string& s)
    {
        s.clear();

        char buff[129];
        size_t i = 0;

        char ch;
        ch = in.get();
        while (ch != ' ' && ch != '\n')
        {
            buff[i++] = ch;
            if (i == 128)
            {
                buff[i] = '\0';
                s += buff;
                i = 0;
            }
            ch = in.get();
        }

        if (i != 0)
        {
            buff[i] = '\0';
            s += buff;
        }

        return in;
    }*/
    //自己的版本
    istream& operator>>(istream& in, string& s)
    {
        char ch;
        ch = in.get();
        while (ch != '\n' && ch != '\0')
        {
            s += ch;
            ch = in.get();
        }
        return in;
    }

私有成员

  • _str 是一个指向字符数组(C-style string)的指针,用于存储字符串的字符序列。

  • _size 是一个用于记录字符串当前长度的变量,即字符串中实际包含的字符数量。

  • _capacity 是一个用于记录字符串当前内存容量的变量,即分配给字符串的字符数组的大小。

  • 这样的设计是为了支持动态字符串的存储和操作。当字符串长度超过当前内存容量时,可以通过重新分配更大的内存空间来保证字符串的存储能力。而 _str 指针则可以指向新分配的内存空间,以容纳更多的字符序列。

 private:
        char* _str;
        size_t _size;
        size_t _capacity;

构造函数

  • 构造函数中的语法 const char* str = "" 定义了一个默认参数。如果在创建对象时不传入参数,那么默认会将一个空字符串赋值给 str。如果传入参数,则使用传入的字符串来初始化新对象。

  • 在构造函数中,首先使用 C 标准库函数 strlen 来计算 str 字符串的长度,并将其保存到成员变量 _size 中。然后,根据字符串长度计算出需要分配的存储空间,并将其保存到成员变量 _capacity 中。

  • 接下来使用 new 运算符在堆上动态分配内存,分配的空间大小为 _capacity + 1,因为字符串末尾要以字符 '\0' 结束。然后使用 C 标准库函数 strcpy 将 str 字符串的内容复制到新分配的内存空间中。

  • 最后,将指针变量 _str 指向新分配的内存空间,完成 C++ 字符串的构造过程。

string(const char* str = "")//构造函数
            :_size(strlen(str))
            , _capacity(_size)
        {
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }

拷贝构造函数

  • 在拷贝构造函数中,首先初始化成员变量 _capacity、_size 和 _str,它们分别表示字符串的容量、大小和存储内容的指针。

  • 然后,在构造函数内部创建了一个名为 tmp 的临时字符串对象,并通过传入的参数 s 的 _str 成员变量来初始化它。这里不能直接传入 s,而是使用 s._str,是因为直接传入 s 会导致递归调用拷贝构造函数,而我们需要调用的是构造函数。

  • 接下来,通过调用 swap 函数,将临时字符串对象 tmp 和当前对象的内容进行交换。这一步中,实际上是交换了 _str 指针指向的内存空间,从而实现了将原始字符串对象的内容复制给新对象的目的。

  • 最终,根据交换后的内容,临时字符串对象 tmp 会自动被销毁,同时也会自动释放内存空间。

 string(const string& s)//拷贝构造函数
            :_capacity(0)
            , _size(0)
            , _str(nullptr)
        {
            string tmp(s._str);//这里不能传s,原因是要调用构造函数而不是拷贝构造函数
            swap(tmp);
        }

赋值运算符的重载

  • 在赋值运算符重载函数中,首先创建了一个名为 tmp 的临时字符串对象,并通过传入的参数 s 调用拷贝构造函数初始化它。

  • 接下来,调用 swap 函数,将临时字符串对象 tmp 和当前字符串对象的内容进行交换。这一步中,实际上是交换了 _str 指针指向的内存空间,从而实现了将原始字符串对象的内容复制给当前对象的目的。

  • 最后,返回当前字符串对象的引用,以支持链式赋值操作。

    string& operator=(const string& s)
        {
            string tmp(s);
            swap(tmp);
            return *this;
        }

析构函数

  • 在析构函数中,首先使用 delete[] 关键字释放之前在堆上动态分配的 _str 成员变量指向的内存空间。这是为了避免发生内存泄漏,释放资源以确保不再使用该内存空间。

  • 接下来,将指针 _str 赋值为 nullptr,以防止在使用已释放的内存时发生未定义的行为。

  • 最后,将成员变量 _size 和 _capacity 的值都设为 0,以标记字符串的大小和容量为 0,表示该字符串对象已经被析构销毁。

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

resize函数

  • resize 函数接受两个参数:新的字符串大小 n 和要填充的字符 c(可选,默认为结束符 '\0')。该函数首先使用 strlen 函数获取当前字符串的长度 len。然后根据不同情况进行处理:

  • 如果新的字符串大小 n 大于字符串的容量 _capacity,表示需要增加字符串的容量以容纳更多的字符。这里通过调用 reserve 函数来增加字符串的容量,保证足够存放 n 个字符,并且在剩余空间中填充字符 c。循环从 len + 1 开始,一直到容量 _capacity,将字符 c 追加到字符串中。

  • 如果新的字符串大小 n 不大于字符串的容量 _capacity,表示不需要增加字符串的容量。此时,如果 n 小于当前字符串的长度 len,需要将字符串截断到指定大小,即将第 n 个字符设置为结束符 '\0'。如果 n 大于等于当前字符串的长度 len,则不需要进行额外操作。

  • 最后,更新字符串的大小 _size 为新的字符串大小 n。

void resize(size_t n, char c = '\0')
        {
            size_t len = strlen(_str);
            if (n > _capacity)
            {
                reserve(n);
                for (int i = len + 1; i < _capacity; i++)
                {
                    (*this) += c;
                }
            }
            else
            {
                _str[n] = '\0';
            }
            _size = n;
        }

reserve函数

  • 这是一个 C++ 字符串类中的 reserve 函数,用于预留足够的容量来存储字符串。

  • 在 reserve 函数中,首先判断传入的参数 n 是否大于当前字符串的容量 _capacity。如果大于,则需要进行扩容操作。

  • 创建了一个名为 tmp 的字符数组指针,通过使用 new 运算符在堆上分配了 n+1 个字符的内存空间。这里 n+1 是为了包含字符串的结尾字符 \0。

  • 然后,使用 strcpy 函数将原始字符串 _str 的内容复制到新分配的内存空间 tmp 中。

  • 接下来,使用 delete[] 运算符释放原始字符串 _str 指向的内存空间,以防止出现内存泄漏。

  • 将指针 _str 更新为指向新分配的内存空间 tmp,使其指向新的字符串内容。

  • 最后,将字符串的容量 _capacity 更新为 n,表示字符串已经具备了预留的容量。

void reserve(size_t n)
        {
            if (n > _capacity)
            {
                char* tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;

                _capacity = n;
            }
        }

push_back 函数

  • 在 push_back 函数中,首先判断当前字符串的大小 _size 是否已经达到了容量 _capacity,如果已经达到,则通过调用字符串类内部的 reserve 函数进行扩容,以腾出更多的空间来存储新的字符。

  • 当确保有足够的容量后,将字符 c 插入到字符串的末尾 _str[_size],并将 _size 的值加一。最后,在末尾添加一个空字符 \0,保证字符串的完整性。

void push_back(char c)//尾插一个字符
        {
            if (_size >= _capacity)//不要去改变_capacity
            {
               
                reserve(_capacity == 0 ? 4 : _capacity * 2);
            }

            _str[_size] = c;
            _size++;
            _str[_size] = '\0';
        }

append 函数

  • 在 append 函数中,首先获取待追加字符数组 str 的长度 len,使用 strlen 函数计算得到。

  • 接着,判断当前字符串的大小 _size 加上待追加字符数组的长度 len 是否超过了容量 _capacity。如果超过了容量,则通过调用字符串类内部的 reserve 函数进行扩容,以腾出足够的空间来存储新的字符。

  • 当确保有足够的容量后,使用 strcpy 函数将字符数组 str 的内容复制到字符串的末尾 _str + _size,即从 _str 的第 _size 个位置开始复制。

  • 最后,将 _size 的值增加 len,表示字符串的大小已经扩展到了追加后的长度。

  • 需要注意的是,为了保证字符串的完整性,最后需要手动添加一个空字符 \0,以结束字符串。

  • 与 push_back 函数相比,append 函数可以一次性追加多个字符,效率较高。适用于需要一次性追加多个字符或者字符数组的情况。而 push_back 则适用于单个字符的追加。

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

            strcpy(_str + _size, str);
            _size += len;
        }

[]运算符重载

  • 在函数体内,通过使用 assert 宏来判断指定的下标是否越界,如果越界则会触发一个断言错误并终止程序的执行,从而避免了对无效位置进行访问。

  • 然后,根据运算符的重载类型(即 const 和非 const),返回私有成员变量 _str 中对应下标位置的字符的引用或常量引用,从而实现对字符串中字符的读写操作。

  • 使用 [] 运算符可以方便地访问字符串对象中的任意字符,类似于数组的使用方式。

 //[]运算符重载
        char& operator[](size_t index)
        {
            assert(index < _size);
            return _str[index];
        }

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

+=运算符重载

  • 第一个重载函数 operator+=(char c) 接受一个字符 c 作为参数。在函数体内,调用了字符串类的 push_back 函数,将字符 c 追加到字符串的末尾。然后,返回当前字符串对象的引用 *this。

  • 第二个重载函数 operator+=(const char* str) 接受一个字符数组 str 作为参数。在函数体内,调用了字符串类的 append 函数,将字符数组 str 追加到字符串的末尾。然后,返回当前字符串对象的引用 *this。

  string& operator+=(char c)
        {
            push_back(c);
            return *this;
        }

        string& operator+=(const char* str)
        {
            append(str);
            return *this;
        }

capacity函数

  • 这是 C++ 字符串类中的 capacity 函数,用于获取字符串对象的容量大小。

  • 在函数体内,直接返回私有成员变量 _capacity 的值。该变量表示字符串对象已经预分配的空间大小,即在不扩容的情况下,该字符串对象最多可以存储多少个字符。

  • 使用 capacity 函数可以帮助我们了解当前字符串对象的容量大小,以便更好地管理内存分配和释放,避免浪费或者不足的情况发生。

  size_t capacity()const
        {
            return _capacity;
        }

empty函数

  • 这是 C++ 字符串类中的 empty 函数,用于判断字符串对象是否为空。

  • 在函数体内,通过比较私有成员变量 _size 是否等于 0,来判断字符串是否为空。如果 _size 等于 0,表示字符串中没有任何字符,即为空;否则,表示字符串中至少包含一个字符,即不为空。

 bool empty()const
        {
            return _size == 0;
        }
    

clear函数

  • 在函数体内,首先将字符串对象 _str 的第一个字符 _str[0] 设置为 '\0',即空字符,表示字符串为空。

  • 然后,将私有成员变量 _size 设置为 0,表示字符串中没有任何字符。

  • 通过调用 clear 函数可以将字符串对象清空,使其不包含任何字符。

 void clear()//清空string对象
        {
            _str[0] = '\0';
            _size = 0;
        }

swap函数

  • 在函数体内,通过使用 std::swap 函数来交换私有成员变量 _str、_size 和 _capacity 与另一个字符串对象 s 的对应成员变量的值。

  • std::swap 是 C++ 标准库中的一个通用函数模板,用于交换两个对象的值。它会根据对象的类型自动选择最高效的交换方式,从而避免了手动实现交换逻辑的繁琐和潜在的错误。

  • 通过调用 swap 函数,可以快速且安全地交换两个字符串对象的内容。

 void swap(string& s)//string的交换函数,是现代写法的基础(包工头写法
        {
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }

size函数

  • 在函数体内,直接返回私有成员变量 _size 的值,表示字符串中包含 _size 个字符,即为有效数据的个数。

  • 使用 size 函数可以方便地获取字符串中字符的数量,可以用于数组越界和其他处理中。

  const size_t size()const//string有效数据个数
        {
            return _size;
        }

迭代器部分的模拟实现

  • 在代码中,使用 typedef 关键字定义了一个名为 iterator 的别名,它表示指向字符的指针类型。

  • 然后,重载了 begin() 和 end() 函数,分别用于返回字符串对象的起始位置和结束位置的迭代器。

  • 对于非常量对象,begin() 函数直接返回私有成员变量 _str,即指向字符串开头的指针。而 end() 函数返回 _str + _size,即指向字符串结尾下一个位置的指针。

  • 对于常量对象,也重载了 begin() 和 end() 函数,返回相同的迭代器,但是声明为常量迭代器,表示在常量对象上不允许修改字符值。

  • 通过返回迭代器,可以方便地遍历字符串对象中的字符,并进行各种操作。

 //迭代器部分
        typedef char* iterator;

        iterator begin()
        {
            return _str;
        }

        iterator end()
        {
            return _str + _size;
        }

        const iterator begin() const
        {
            return _str;
        }

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

c_str函数

  • c_str() 函数通常用于将字符串对象转换为 C 风格的字符串,以便与需要接受 C 风格字符串作为参数的函数进行交互。

//提供私有成员_str
        const char* c_str()const
        {
            return _str;
        }

find函数

  • 函数的参数包括一个指向字符数组的指针 s 和一个可选的起始搜索位置 pos(默认为0)。

  • 首先,使用 assert 断言确保 pos 的值小于字符串的长度 _size,以避免越界访问。

  • 接下来,使用标准库函数 strstr 在字符串 _str 的 pos 位置之后搜索指定的子串 s。如果找到了匹配的子串,则 strstr 函数返回指向该子串的指针;如果没有找到,则返回空指针。

  • 如果 tmp 是空指针(即找不到匹配的子串),则表示查找失败,函数返回特殊值 npos(通常定义为 size_t(-1),表示无效的位置)。

  • 如果找到了匹配的子串,函数会继续调用 find 函数,传入子串的第一个字符 *tmp,以在整个字符串中找到该字符第一次出现的位置,并将其作为结果返回。

  • 需要注意的是,find 函数返回的是子串第一次出现的位置,而不是子串本身。如果需要获取子串本身,可以使用字符串类的 substr 函数进行切片操作。

  • 此外,该代码中的 find 函数是一个 const 成员函数,表示它不会修改字符串对象的内容。

  size_t find(const char* s, size_t pos = 0) const
        {
            assert(pos < _size);
            char* tmp = strstr(_str + pos, s);
            if (tmp == nullptr)
            {
                return npos;
            }
            return find(*tmp);
        }

insert函数

  • 第一个 insert 函数接受两个参数:一个是要插入的字符 c,另一个是插入位置 pos。该函数首先使用断言 assert 确保插入位置不超出字符串的范围。然后,如果字符串当前的长度 _size 已经达到了其容量 _capacity,则通过调用 reserve 函数增加字符串的空间以容纳新字符。接下来,将 pos 之后的所有字符依次向后挪一位,为新字符腾出空间。最后,将新字符插入到指定位置,更新字符串的长度并返回字符串对象本身的引用。

  • 第二个 insert 函数与第一个函数类似,但它接受的参数是一个字符指针 str,表示要插入的字符串。该函数的实现类似于第一个函数,只不过需要多次插入字符,并且需要移动更多的字符位置。在插入前,该函数还会先计算待插入字符串的长度 len。最后,更新字符串的长度并返回字符串对象本身的引用。

 // 在pos位置上插入字符c/字符串str,并返回该字符的位置

        string& insert(size_t pos, char c)
        {
            assert(pos <= _size);//pos=size相当于尾插
            if (_size >= _capacity)//不要去改变_capacity
            {
                reserve(_capacity == 0 ? 4 : _capacity * 2);
            }
            size_t end = _size + 1;
            while (end != pos)
            {
                _str[end] = _str[end-1];
                end--;
            }
            _str[pos] = c;
            _size++;
            return *this;
        }

        string& insert(size_t pos, const char* str)
        {
            assert(pos <= _size);
            size_t len = strlen(str);
            if (_size+len >= _capacity)//不要去改变_capacity
            {
                reserve(_size+len);
            }
            size_t end_new = _capacity;
            size_t end_old = _size;
            while (end_old > pos)
            {
                _str[end_new] = _str[end_old];
                end_old--;
                end_new--;
            }
            _str[end_new] = _str[pos];
            for (int i = 0; i < len; i++)
            {
                _str[pos++] = str[i];
            }
            _size+=len;
            return *this;
        }

erase函数

  • erase 函数接受两个参数:要删除的元素的起始位置 pos,和要删除的元素的长度 len(可选,默认为 npos)。该函数首先使用断言 assert 确保删除位置不超出字符串的范围。然后根据 len 的值进行不同的处理:

  • 如果 len 的值为默认值 npos 或者 pos + len 大于等于字符串的长度 _size,表示要删除 pos 位置之后的所有元素,则将 pos 位置上的元素设置为结束符 '\0',并更新字符串的长度 _size 为 pos。

  • 否则,需要删除指定位置 pos 后面的 len 个元素。首先定义一个变量 begin,表示要删除的元素之后的第一个元素的位置。然后通过循环将 begin 位置及其后面的所有元素向前挪动 len 个位置,以覆盖要删除的元素。最后,更新字符串的长度 _size 减去 len。

  • 这样,删除成功后,字符串中就会被删除的元素占据的位置填补上相应的元素,并且字符串的长度也会相应调整。

  // 删除pos位置上的元素,并返回该元素的下一个位置
        void erase(size_t pos, size_t len = npos)
        {
            assert(pos < _size);

            if (len == npos || pos + len >= _size)
            {
                _str[pos] = '\0';
                _size = pos;
            }
            else
            {
                size_t begin = pos + len;
                while (begin <= _size)
                {
                    _str[begin - len] = _str[begin];
                    ++begin;
                }
                _size -= len;
            }
        }

比较运算符的重载

  • 首先,这些比较运算符都接受一个字符串对象 s 作为参数,并以引用形式传递。接下来,按照运算符的定义进行逐个实现:

  • 小于运算符(<)通过调用 strcmp 函数比较当前字符串 _str 和参数字符串 s._str 的大小。如果 _str 小于 s._str,则返回 true;否则返回 false。

  • 小于等于运算符(<=)通过在小于运算符之后添加一个等于运算符组成。如果当前字符串小于 s 或者当前字符串等于 s,则返回 true;否则返回 false。

  • 大于运算符(>)通过在小于等于运算符之前添加逻辑非运算符(!)来实现。如果当前字符串不小于等于 s,即大于 s,则返回 true;否则返回 false。

  • 大于等于运算符(>=)通过在大于运算符之前添加逻辑非运算符来实现。如果当前字符串不大于 s,即小于 s,则返回 true;否则返回 false。

  • 等于运算符(==)通过调用 strcmp 函数比较当前字符串和参数字符串的大小。如果相等,则返回 true;否则返回 false。

  • 不等于运算符(!=)通过在等于运算符之前添加逻辑非运算符来实现。如果当前字符串不等于 s,则返回 true;否则返回 false。

  • 这样,就可以使用比较运算符对字符串对象进行大小比较操作。

   bool operator<(const string& s)
        {
            if (strcmp(_str, s._str) < 0)
            {
                return true;
            }
            return false;
        }

        bool operator<=(const string& s)
        {
            if ((*this) < s || (*this) == s)
            {
                return true;
            }
            return false;
        }

        bool operator>(const string& s)
        {
            return !(*this <= s);
        }

        bool operator>=(const string& s)
        {
            return !(*this < s);
        }

        bool operator==(const string& s)
        {
            if (strcmp(_str, s._str) == 0)
            {
                return true;
            }
            return false;
        }

        bool operator!=(const string& s)
        {
            return!((*this) == s);
        }

流插入流提取运算符重载

  • 首先,流插入运算符重载函数接受一个输出流对象 out 和一个字符串对象 s 作为参数,并以引用形式传递。实现过程中遍历字符串 _str 的每个字符并输出到 out 流中,最后返回输出流对象 out。

  • 比较而言,流提取运算符重载函数接受一个输入流对象 in 和一个自定义的字符串对象 s 作为参数。实现过程中逐个读取输入流中的字符,如果字符不是换行符或者字符串终止符,则将其添加到字符串对象 s 中,最后返回输入流对象 in。

//流插入流提取的运算符重载
    ostream& operator<<(ostream& out, const hqj::string& s)
    {
        for (int i = 0; i < s.size(); i++)
        {
            out << s._str[i];
        }
        return out;
    }
//自己的版本
    istream& operator>>(istream& in, string& s)
    {
        char ch;
        ch = in.get();
        while (ch != '\n' && ch != '\0')
        {
            s += ch;
            ch = in.get();
        }
        return in;
    }

你可能感兴趣的:(c++,c++,数据结构)