【C++】STL——string模拟实现(2)

简介: 【C++】STL——string模拟实现(2)

四、字符串访问函数

1.operator[ ]()

[ ]运算符重载是为了让string类能够实现下标的访问

//可读可写
char& operator[](size_t pos)
{
  assert(pos < _size);
  return _str[pos];
}
//可读不可写
const char& operator[](size_t pos) const
{
  assert(pos < _size);
  return _str[pos];
}

2.迭代器

       相比其他容器的迭代器,string类的迭代器相对简单,实际上是char*的typedef;函数后面的const表示的是this不能被修改;

typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
  return _str;//返回字符串第一个位置
}
iterator end()
{
  return _str + _size;//返回'\0'的地址
}
const_iterator begin() const
{
  return _str;
}
const_iterator end() const
{
  return _str + _size;
}

五、关系运算符重载函数

bool operator<(const string& s1, const string& s2)
{
  return strcmp(s1.c_str(), s2.c_str()) < 0;
}
bool operator==(const string& s1, const string& s2)
{
  return strcmp(s1.c_str(), s2.c_str()) == 0;
}
//实现两种比较其他的可以复用
bool operator<=(const string& s1, const string& s2)
{
  return s1 < s2 || s1 == s2;
}
bool operator>=(const string& s1, const string& s2)
{
  return !(s1 < s2);
}
bool operator>(const string& s1, const string& s2)
{
  return !(s1 <= s2);
}
bool operator!=(const string& s1, const string& s2)
{
  return !(s1 == s2);
}

六、流提取、流插入运算符重载

//流插入 <<
ostream& operator<<(ostream& out, const string& s)
{
  //方式一
  for (auto ch : s)
  {
    out << ch;
  }
  //方式二
  for (size_t i = 0; i < s.size(); ++i)
  {
    out << s[i];
  }
  //方式三 
  //out << s.c_str();//不能这样写
  return out;
}
//流提取 >>
istream& operator>>(istream& in, string& s)
{
  s.clear();
  char ch = in.get();
  while (ch != ' ' && ch != '\n')//利用循环可以连续输入
  {
    s += ch;
    ch = in.get();
  }
  return in;
}

完整代码

namespace mlxg3
{
  class string
  {
  public:
    /******************迭代器********************/
    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;
    }
    /******************构造函数********************/
    string(const char* str = "")
      :_size(strlen(str))
      , _capacity(_size)
    {
      _str = new char[_capacity + 1];
      strcpy(_str, str);
    }
    /******************拷贝构造********************/
    //s2(s1)
    //传统写法
    /*
    string(const string& s)
      :_size(s._size)
      , _capacity(s._capacity)
    {
      _str = new char[_capacity + 1];
      strcpy(_str, s._str);
    }
    */
    /******************赋值重载********************/
    /*
    string& operator=(const string& s)
    {
      if (this != &s)
      {
        char* tmp = new char[s._capacity + 1];
        strcpy(tmp, s._str);
        delete[] _str;
        _str = tmp;
        _size = s._size;
        _capacity = s._capacity;
      }
      return *this;
    }
    */
    /******************拷贝构造与赋值重载现代写法********************/
    //现代写法
    void swap(string& s)
    {
      std::swap(_str, s._str);
      std::swap(_size, s._size);
      std::swap(_capacity, s._capacity);
    }
    //s2(s1)
    string(const string& s)
      :_str(nullptr)
      , _size(0)
      , _capacity(0)
    {
      string tmp(s._str);
      //this->swap(tmp);
      swap(tmp);
    }
    string& operator=(string s)
    {
      swap(s);
      return *this;
    }
    /******************析构函数********************/
    ~string()
    {
      delete[] _str;
      _str = nullptr;
      _size = _capacity = 0;
    }
    /******************增删查改、增容********************/
        //返回c形式的字符串
    const char* c_str() const
    {
      return _str;
    }
        //返回有效字符的个数
    size_t size() const
    {
      return _size;
    }
        //返回有效容量的大小
    size_t size() const
    {
      return _size;
    }
        //[]重载
    char& operator[](size_t pos)
    {
      assert(pos < _size);
      return _str[pos];
    }
        //[]重载 --- const
    const char& operator[](size_t pos) const
    {
      assert(pos < _size);
      return _str[pos];
    }
        //reserve增容
    void reserve(size_t n)
    {
      if (n > _capacity)
      {
        char* tmp = new char[n + 1];//这里加1是为了给'\0'一个空间
        strcpy(tmp, _str);
        delete[]_str;
        _str = tmp;
        _capacity = n;
      }
    }
        //resize增容
    void resize(size_t n, char ch = '\0')
    {
      if (n <= _size)
      {
        _size = n;
        _str[_size] = '\0';
      }
      else
      {
        if (n > _capacity)
        {
          reserve(n);
        }
        memset(_str + _size, ch, n - _size);
        _size = n;
        _str[_size] = '\0';
      }
    }
        //尾插字符
    void push_back(char ch)
    {
      /*
      if (_size == _capacity)
      {
        //增容
        reserve(_capacity == 0 ? 4 : _capacity * 2);
      }
      _str[_size] = ch;
      ++_size;
      _str[_size] = '\0';
      */
      insert(_size, ch);//复用
    }
    //尾插字符串 
    void append(const char* str)
    {
      /*
      size_t len = strlen(str);
      if (_size + len > _capacity)//不需要考虑给\0空间
      {
        reserve(_size + len);
      }
      strcpy(_str + _size, str);
      _size += len;
      */
      insert(_size, str);//复用
    }
    //尾插字符 --- +=重载
    string& operator+=(char ch)
    {
      push_back(ch);
      return *this;
    }
    //尾插字符串 --- +=重载
    string& operator+=(const char* str)
    {
      append(str);
      return *this;
    }
    //查找第一个匹配的字符
    size_t find(char ch)
    {
      for (size_t i = 0; i < _size; ++i)
      {
        if (ch == _str[i])
        {
          return i;
        }
      }
      return npos;
    }
    //查找第一个匹配的字符串
    size_t find(const char* s, size_t pos = 0)
    {
      const char* ptr = strstr(_str + pos, s);
      if (ptr == nullptr)
      {
        return npos;
      }
      else
      {
        return ptr - _str;
      }
    }
    //在pos位置插入一个字符
    string& insert(size_t pos, char ch)
    {
      assert(pos <= _size);
      if (_size == _capacity)
      {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
      }
      size_t end = _size + 1;
      while (end > pos)
      {
        _str[end] = _str[end - 1];
        --end;
      }
      _str[pos] = ch;
      ++_size;
      return *this;
    }
    //在pos位置插入一个字符串
    string& insert(size_t pos, const char* s)
    {
      assert(pos <= _size);
      size_t len = strlen(s);
      if (_size + len > _capacity)
      {
        reserve(_size + len);
      }
      size_t end = _size + len;
      while (end >= pos + len)
      {
        _str[end] = _str[end - len];
        --end;
      }
      strncpy(_str + pos, s, len);
      _size += len;
      return *this;
    }
    //从pos位置开始删除字符
    string& erase(size_t pos = 0, size_t len = npos)
    {
      assert(pos < _size);
      if (len == npos || pos + len >= _size)
      {
        _str[pos] = '\0';
        _size = pos;
      }
      else
      {
        strcpy(_str + pos, _str + pos + len);
        _size -= len;
      }
      return *this;
    }
    //将字符串置空
    void clear()
    {
      _str[0] = '\0';
      _size = 0;
    }
  private:
    char* _str;
    size_t _size;
    size_t _capacity;//有效字符的空间数
    static const size_t npos;
  };
    //定义npos(为了和库一致)
  const size_t string::npos = -1;
  /*
     字符串s1      字符串s2
    "abcd"   和   "abcd"    ----false
    "abcd"   和   "abcde"   ----true
    "abcde"   和   "abcd"   ----false
  */
    //字符串的比较 --- 关系运算符的重载
  bool operator<(const string& s1, const string& s2)
  {
    return strcmp(s1.c_str(), s2.c_str()) < 0;
  }
  bool operator==(const string& s1, const string& s2)
  {
    return strcmp(s1.c_str(), s2.c_str()) == 0;
  }
  bool operator<=(const string& s1, const string& s2)
  {
    return s1 < s2 || s1 == s2;
  }
  bool operator>=(const string& s1, const string& s2)
  {
    return !(s1 < s2);
  }
  bool operator>(const string& s1, const string& s2)
  {
    return !(s1 <= s2);
  }
  bool operator!=(const string& s1, const string& s2)
  {
    return !(s1 == s2);
  }
    //流插入重载 
  ostream& operator<<(ostream& out, const string& s)
  {
    //方式一
    for (auto ch : s)
    {
      out << ch;
    }
    //方式二
    for (size_t i = 0; i < s.size(); ++i)
    {
      out << s[i];
    }
    //方式三 
    //out << s.c_str();//不能这样写
    return out;
  }
    //流提取重载 
  istream& operator>>(istream& in, string& s)
  {
    s.clear();
    char ch = in.get();
    while (ch != ' ' && ch != '\n')
    {
      s += ch;
      ch = in.get();
    }
    return in;
  }
}
目录
相关文章
|
22天前
|
编译器 C语言 C++
【c++丨STL】list模拟实现(附源码)
本文介绍了如何模拟实现C++中的`list`容器。`list`底层采用双向带头循环链表结构,相较于`vector`和`string`更为复杂。文章首先回顾了`list`的基本结构和常用接口,然后详细讲解了节点、迭代器及容器的实现过程。 最终,通过这些步骤,我们成功模拟实现了`list`容器的功能。文章最后提供了完整的代码实现,并简要总结了实现过程中的关键点。 如果你对双向链表或`list`的底层实现感兴趣,建议先掌握相关基础知识后再阅读本文,以便更好地理解内容。
26 1
|
1月前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
51 7
|
2月前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
96 4
|
2月前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
101 5
|
2月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
78 2
|
2月前
|
存储 算法 Linux
【c++】STL简介
本文介绍了C++标准模板库(STL)的基本概念、组成部分及学习方法,强调了STL在提高编程效率和代码复用性方面的重要性。文章详细解析了STL的六大组件:容器、算法、迭代器、仿函数、配接器和空间配置器,并提出了学习STL的三个层次,旨在帮助读者深入理解和掌握STL。
82 0
|
1月前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
46 0
|
11天前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
51 18
|
11天前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
37 13
|
11天前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
37 5

热门文章

最新文章