类对象的访问以及遍历操作
operator[]
由于string类的底层是连续的空间,因此可以实现使用[]+下标来访问并修改string对象的内容,需要注意一下的是最好需要重载一个const类型的成员函数,针对传入类型为const变量时使用。
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
访问和遍历string对象操作
for+[]下标访问
void Teststring()
{
string s("hello Bit");
for (size_t i = 0; i < s.size(); ++i)
{
cout << s[i] << " ";
}
}
迭代器访问
void Teststring()
{
string s("hello Bit");
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout<<endl;
string::reverse_iterator rit = s.rbegin();
while (rit != s.rend())
{
cout << *rit << " ";
rit++;
}
}
可以使用反向迭代器进行逆序访问
范围for
void Teststring()
{
string s("hello Bit");
for (auto ch : s)
{
cout << ch << " ";
}
}
实际上范围for的底层还是由迭代器实现的,只有先实现了string类的迭代器才能正常使用范围for,下面会介绍如何实现string的迭代器。
at
at和[]功能类似,都是借助下标来访问string对象的内容,不同的是他们处理错误的方式不同,[]处理越界的方式是断言报错,at采用的方式是抛异常
void test_string5()
{
string s1("hello wrold");
cout<<s1.at(1)<<endl;
cout << s1[1] << endl;
}
void test_string5()
{
string s1("hello wrold");
cout<<s1.at(1)<<endl;
cout << s1[1] << endl;
cout << s1.at(15) << endl;
cout << s1[15] << endl;
}
string类的修改操作
push_back
push_back是给string尾插一个字符,需要考虑到扩容的问题,一般扩容是以2倍扩容,这边可以直接调用之前实现过的reserve函数来进行扩容
void push_back(char ch)
{
if (_size == _capacity)
{
reserve(_capacity * 2);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
void test_string6()
{
hyx::string s1("hello wrold");
cout << s1 << endl;
s1.push_back('h');
s1.push_back('h');
s1.push_back('h');
cout << s1 << endl;
}
append
append和push_back的区别在于append是在字符串后面加一个字符串。
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
strcpy(_str + _size, str);
_size += len;
}
void test_string7()
{
hyx::string s1("hello wrold");
cout << s1 << endl;
s1.append("hello");
cout << s1 << endl;
}
operator+=
这里运算符重载+=是结合了push_back和append的功能,既可以尾插字符也可以尾插字符串,通过函数重载即可实现。
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
void test_string8()
{
hyx::string s1("hello wrold");
cout << s1 << endl;
s1+='h';
cout << s1 << endl;
s1 += "hello ";
cout << s1 << endl;
}
insert和erase
string类对象还支持中间位置的插入删除,使用insert和erase即可实现,但是需要注意的是string类对于中间位置的插入删除需要移动数据,消耗会比较大。
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;
}
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, s, len);
_size += len;
return *this;
}
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;
}
string类操作
c_str
c_str是将string类转换为C类型的字符串
const char* c_str() const
{
return _str;
}
void test_string9()
{
hyx::string s1("hello wrold");
cout << s1.c_str() << endl;
}
这里需要注意的是之前能够直接使用流插入运算符来输出string对象是因为重载了流插入运算符,如果没有进行流插入运算符,则不能直接输出
find
find函数是用来查找string对象中的内容,既可以查找字符串,也可以查找单个字符,这里需要注意的是查找字符串可以从指定位置进行查找,默认从头进行查找
size_t find(char ch)
{
for (size_t i = 0; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return npos;
}
size_t find(char* s, size_t pos = 0)
{
const char* str = strstr(_str + pos, s);
if (str == nullptr)
{
return npos;
}
else
{
return str - _str;
}
}
void test_string10()
{
hyx::string s1("hello wrold");
cout << s1[s1.find('o')] << endl;
cout << s1[s1.find("rol")] << endl;
}
npos
这里上面find,erase中都用到这个npos变量,这个变量是干什么的呢?实际上他是一个size_t 类型静态常量,大小定义为-1,由于是size_t类型,因此这个数可以用来代表整个字符串长度,他的定义如下:
static const size_t npos;
const size_t string::npos = -1;
<</>>
之前在友元函数一节中讲述过这种自定义类型,想要重载流插入、流提取运算符并且正常使用操作符和操作数,需要使用友元函数。
std::ostream& operator<<(std::ostream& out, const string& s)
{
for (size_t i=0;i<s.size();i++)
{
out << s[i];
}
return out;
}
std::istream& operator>>(std::istream& in, string& s)
{
s.clear();
char ch = in.get();
while (ch != ' ' && ch != '\n')
{
s += ch;
ch = in.get();
}
return in;
}
迭代器
string对象中的迭代器实际上是一个char*类型的指针。
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;
}
实现了迭代器后,可以使用迭代器访问string对象内容以及使用范围for,但是在string类中迭代器的优势并不明显,效率和方便性不如[]下标进行随机访问的方式,但是在后面的其他类中,会体现出他的价值。
|