运算符重载
- 赋值运算符
也就是说我们可以直接用string对象或者字符串来给新的对象赋值。
int main() { string s; s = "123456"; string s1("xxx"); s = s1; return 0; }
- +和+=
从这两张图我们就可以看出来,+=是成员函数,而+是全局函数。我们需要尾插是可以用+=也可以用+,但是+的代价是很大的,我们尽量使用+=。
int main() { string s("123"); s += "456"; s += '7'; s = s + '8'; return 0; }
模拟实现
string& operator+=(const char s) { push_back(s); return *this; } string& operator+=(const char* s) { append(s); return *this; }
- 流插入和流提取
也就是说,我们可以直接使用cout和cin来对sting对象来进行输入和输出了。
模拟实现
- 流提取
我们可以一个字符一个字符的提取,因为_str为私有的,我们无法访问,我们也可以使用友元,但是我们这里一个字符一个字符的访问。
ostream& operator<<(ostream& out, const string& s) { int end = s.size(); for (int i = 0; i < end; i++) { out << s[i]; } return out; }
- 流插入
流插入也一样,我们一个字符一个字符的读,当读到‘\n’或者空格就停止,但是cin和scanf都无法读空格和换行,这是就需要一个函数,cin.get(),它的功能就和C语言的getcahr很相似。
istream& operator>>(istream& in, string& s) { s.clear(); char ch = in.get(); while (ch != ' ' && ch != '\n') { s += ch; ch = in.get(); } return in; }
int main() { string s; cin >> s; cout << s << endl; return 0; }
- 比较运算符
我们可以直接使用比较运算符来对sting对象和字符串等进行比较了。
模拟实现
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& operator+=(const char s) { push_back(s); return *this; } string& operator+=(const char* s) { append(s); return *this; } bool operator<(const string& s) { return strcmp(_str, s._str) < 0; } bool operator==(const string& s) { return strcmp(_str, s._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); }
push_back和append
- push_back
尾插一个字符
- append
尾插一段字符串,库里面给的接口很多,我们都不是很常用,我们都喜欢用+=。
模拟实现
void push_back(const char ch) { if (_size == _capacity) { reserve(_capacity == 0 ? 4 : _capacity * 2); } _str[_size++] = ch; _str[_size] = '\0'; } void append(const char* s) { size_t len = strlen(s); if (_size + len > _capacity) { reserve(_size+len); } strcpy(_str + _size, s); _size += len; }
insert和erase
- insert
我们一般用的都是在某个位置插入一个字符或者字符串。
模拟实现
string& insert(size_t pos, char ch) { assert(pos <= _size); if (_size == _capacity) { reserve(_capacity == 0 ? 4 : _capacity * 2); } int end = _size; //必须强转,不然会类型提升,当pos=0时发生死循环 while (end >= (int)pos) { _str[end + 1] = _str[end]; end--; } _str[pos] = ch; _size++; return *this; } string& insert(size_t pos, const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } int end = _size; while (end >= (int)pos) { _str[end + len] = _str[end]; end--; } strncpy(_str + pos, str, len); _size += len; return *this; }
- erase
删除某个位置的len个字符
模拟实现
earse我们需要提供一个npos的半缺省参数,如果不给的话就表示将pos以后得数据都删了。
nops是一个所有类都有的,所以我们可以定义为静态成员变量。
string& erase(size_t pos, size_t len = npos) { assert(pos < _size); if (pos + len > _size || len == npos) { _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; } } public: const static int npos = -1;
查找
- find
我们可以用这个函数来查找字符串或者字符。
int main() { string s("123456"); int i = s.find("23"); int j = s.find('5',2); int x = s.find("123", 2, 3); return 0; }
- rfind
rfind也是查找只不过是从最后开始找。和find相似。
模拟实现
size_t find(char c, size_t pos = 0) const { assert(pos < _size); for (size_t i = pos; i < _size; i++) { if (_str[i] == c) { return i; } } return npos; } size_t find(const char* s, size_t pos = 0) const { size_t len = strlen(s); assert(pos + len < _size); char* str = strstr(_str + pos, s); if (str != nullptr) { return str - _str; } return npos; }
截取字符串
substr
从pos位置开始提取len个字符,不给len直接取到最后。
模拟实现
string substr(size_t pos = 0, size_t len = npos) const { string s; if (len == npos || pos + len > _size) { size_t i = 0; for (i = pos; i <= _size; i++) { s += _str[i]; } return s; } else { size_t i = 0; for (i = pos; i < pos+len; i++) { s += _str[i]; } s += '\0'; return s; } }
获取字符指针
我们知道string是一个类,那我们想要得到底层的那个字符指针怎么获得呢?
我们可以使用c_str这个函数
int main() { string s("123456"); const char* str = s.c_str(); return 0; }
模拟实现
const char* c_str() const { return _str; }
交换对象
swap
对于string有一个专门的swap,可以用来交换两个string对象。
int main() { string s("123456"); string s1("12"); s.swap(s1); cout << s << endl << s1 << endl; return 0; }
模拟实现
void swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); }
特殊读取
我们知道cin和scanf一样,遇到空格或者换行都会提前结束,那我们需要读取的字符串包含空格或者换行怎么办呢,这时候就需要getline了。
int main() { string s; getline(cin, s); cout << s; return 0; }
我们也可以自己指定读取结束的字符。
今天的分享就到这里,感谢大家的关注和支持。