上一篇文章我们讲解了string类的构造、拷贝构造、赋值及其模拟实现
下面是我们本篇文章的主要内容:

char& operator[](size_t pos)
{
assert(pos < strlen(_str));
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < strlen(_str));
return _str[pos];
}
int main()
{
string s1("hello world");
for (int i = 0; i < s1.size(); ++i)
{
cout << s1[i];
}
return 0;
}

也就是说c_str返回的值指向该字符串并且包含“\0”的字符序列,使用c_str( )来打印字符串,当碰到“\0”时就停止(这是因为C/C++中字符串处理函数(如**printf**, cout**,** strcpy**等)都遵循一个约定:将以null字符('\0')作为字符串的结束标志**)。
const char* c_str() const
{
return _str;
}
迭代器:string的迭代器的底层其实就是一个char*的原生指针,所以使用string迭代器只需要像使用普通指针一样即可。但是其他容器的底层不应该否是原生指针。
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
iterator begin() const
{
return _str;
}
iterator end()
{
return _str + _size;
}
iterator end() const
{
return _str + _size;
}然后我们使用迭代器来进行字符串的遍历:
int main()
{
s::string s1("Hello World");
s::string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << "";
it++;
}
}PS:这个地方要注意的是要注意使用的是C++string类中的迭代器还是我们自定义类string中的迭代器。

for的使用:
for (auto e : s1)
{
cout << e << " ";
}
其实范围for的底层机制同样是一个迭代器,我们可以通过下面的方式进行验证,我们将迭代器给注释掉,我们来看一下发生什么:

2.1. push_back

可以看到,push_back的作用是将一个字符添加到原有字符串后面,具体步骤:
但是我们在日常写代码中并不会经常使用push_back,而是使用 += ,所以我们来重载一下 += ,它的实现中也可以服用push_back:
string& operator+=( char ch)
{
push_back(ch);
return *this;
}

这里可以注意到,前面两个接口都是将单个字符添加到已有字符串结尾,而这个接口是将一个字符串添加到原来的字符串,步骤如下:
void append(const char* str)
{
size_t len = _size + strlen(str);
if (len > _capacity)
{
reserve(len);
}
strcpy(_str + _size, str);
_size = len;
//insert(_size, str);
}
与单个字符的重载复用push_back一样,复用appand接口:
string& operator+=(const char* str)
{
append(str);
return *this;
}


string& insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_capacity == _size)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
size_t end = _size + 1;
while (end > pos)
{
_str[end - 1] = _str[end];
--end;
}
_str[pos] = ch;
++_size;
return *this;
}
string& insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (len == 0)
{
return *this;
}
if (_size + len > _capacity)
{
reserve(_size + len);
}
//挪动数据
size_t end = _size + len;
//while(end >= end+len)
while (end > pos+len-1)
{
_str[end] = _str[end-len];
--end;
}
//插入数据
size_t i = 0;
while (i < len)
{
_str[pos+i] = str[i];
++i;
}
_size += len;
return *this;
}

我们看这里提到了一个参数npos:

所以可以知道,earse的作用就是从pos开始,往后len个长度,把这些字符删去。
那其实我们逻辑上删除它只需要将pos位置赋值"\0"即可:

首先找到需要删除的子字符串的后一位,将其定为begin,然后我们需要做的就是将begin后面的所有字符全部往前移动,覆盖掉需要删除的字符:

string& earse(size_t pos, size_t len = std::string::npos)
{
assert(pos < _size);
if (len == std::string::npos || len + pos >= _size)
{
_str[pos] = '\0';
_size = pos;
return *this;
}
else
{
size_t begin = pos + len;
while (begin <= _size)
{
_str[begin - len] = _str[begin];
++begin;
}
_size -= len;
return *this;
}
}

find查找字符串,返回查到的第一个满足的字符:
size_t find(char ch, size_t pos = 0)
{
for (; pos < _size; ++pos)
{
if (_str[pos] == ch)
{
return pos;
}
}
return std::string::npos;
}
size_t find(const char* ch, size_t pos)
{
const char* p = strstr(_str + pos, ch);
if (nullptr == p)
{
return std::string::npos;
}
else
{
return p - _str;
}
}
bool operator < (const string& s)
{
return strcmp(this->c_str(), s.c_str()) < 0;
}
bool operator == (const s::string& s)
{
return strcmp(this->c_str(), s.c_str()) == 0;
}
bool operator<=(const string& s)
{
return *this < s || *this == s;
}
bool operator>(const string& s)
{
return !(*this <= s);
}
bool operator>=(const string& s)
{
return !(*this < s);
}
bool operator!=(const string& s)
{
return !(*this == s);
}对于这段代码有疑问的可以看下【C++】类和对象--类中6个默认成员函数(2) --运算符重载,这里涉及到成员函数隐藏this指针的问题。

reserve的作用就是是个string的容量变成n:
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}

resize是将字符串大小修改为n。
resize和reserve的区别是:reserve只对空间进行处理,但是resize不仅对空间进行影响,而且会改变_size的值。
看下面这个例子,假设空间长度为15,字符串长度为11:

也就是扩容了之后会使用字符串参数填充满:


这种情况下不需要扩容,所以_capacity不会变:


这个时候只会保存原字符串的前n个字符:

代码如下:
//扩空间+初始化
//删除部分数据,保留前n个
void resize(size_t n, char ch = '\0')
{
if (n < _size)
{
_size = n;
_str[_size] = '\0';
}
else
{
if (n > _capacity)
{
reserve(n);
}
for (size_t i = _size; i < n; ++i)
{
_str[i] = ch;
}
_size = n;
_str[_size] = '\0';
}
}(本篇完)