访问及遍历操作
operator[]返回对象下标的元素
begin+ end迭代器,begin是字符串最开始的元素,end是字符串末尾的‘\0’
rbegin + rend反向迭代器
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
#include <iostream> #include <string> using namespace std; int main() { string s("qwert"); cout << s[2] << endl; s = "123456"; string::iterator left1 = s.begin();//可读可写 string::const_iterator left2 = s.begin();//可读不可写 while (left1 != s.end()) { *left1 += 1; cout << *left1; left1++; } cout << endl; while (left2 != s.end()) { cout << *left2; left2++; } cout << endl; string::reverse_iterator left3 = s.rbegin(); string::const_reverse_iterator left4 = s.rbegin(); while (left3 != s.rend()) { *left3 += 1; cout << *left3; left3++; } cout << endl; while (left4 != s.rend()) { cout << *left4; left4++; } cout << endl; return 0; }
C++11语法中的for循环就是与迭代器有关。
这里还有一个类似于operator[]的接口是at,找到的就返回,找不到会抛异常。
string中的swap与C++库中的swap的区别
string::swap
void swap (string& x, string& y);
交换两个同类对象中的成员
#include <iostream> #include <assert.h> using namespace std; int main() { string s1("asdq7777777777777777777"); string s2("qwe"); s1.swap(s2); cout << s1 << endl; cout << s1.size() << endl; cout << s1.capacity() << endl; cout << s2 << endl; cout << s2.size() << endl; cout << s2.capacity() << endl; return 0; }
C++库swap
这是一个模板
template <class T> void swap ( T& a, T& b ) { T c(a); a=b; b=c;//这里其实就相当于调用了构造函数,因为T会有自定义类型 }
平时我们的内置类型都是不需要进行析构和构造的,但是内置类型进入模板之后就需要了。
使用时要注意深浅拷贝问题,自定义类型要调用 = 。
非成员函数
operator>>
operator<<流插入流提取
istream& operator>> (istream& is, string& str);
ostream& operator<< (ostream& os, const string& str);
这个就很熟悉了上面不知道用了多少。
string类的模拟实现
#include <iostream> #include <assert.h> using namespace std; namespace baiye { class string { public: typedef char* iterator; string(const char* s = "")//对象初始化,缺省值有一个隐藏的\0 { _arr = new char[strlen(s) + 1]; strcpy(_arr, s); _size = strlen(_arr); _capacity = _size;//实际可以储存的大小,不算\0的位置 } ~string()//析构 { delete[] _arr; _arr = nullptr; _size = 0; _capacity = 0; } string(const string& s)//拷贝构造 :_arr(nullptr) ,_size(0) ,_capacity(0) { string tmp(s._arr); swap(tmp); } string& operator=(string s)//这里不用引用就是临时变量,我们可以让它成为打工人 { swap(s); return *this; } //iterator iterator begin()const { return _arr; } iterator end()const { return _arr + _size - 1; } // modify const char* c_str()const { return _arr; } void push_back(char c) { if (_size == _capacity) { size_t len = _size == 0 ? 4 : _capacity * 2;//防止空对象扩容失败 reserve(len); } _arr[_size] = c; _size++;//注意\0 _arr[_size] = '\0'; } void append(const char* str) { if (_size + strlen(str) > _capacity) { reserve(_size + strlen(str) + 1);//不能二倍扩容,万一新加的字符串更大就不行了 } strcpy(_arr + _size, str); _size = strlen(_arr); } string& operator+=(char c) { push_back(c); return *this; } string& operator+=(const char* str) { append(str); return *this; } void clear() { _arr[0] = '\0'; _size = 0; } void swap(string& s) { std::swap(_arr, s._arr); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } //capacity size_t size()const//返回长度 { return _size; } size_t capacity()const//返回容量 { return _capacity; } bool empty()const { return _size; } void resize(size_t n, char c = '\0') { if (n <= _size) { _arr[n] = '\0'; _size = n; } else { reserve(n); while (_size < n) { _arr[_size] = c; _size++; } _arr[n] = '\0'; _size = n; } } void reserve(size_t n) { char* tmp = new char[n + 1];//+1是为了算\0 strcpy(tmp, _arr); delete[] _arr; _arr = tmp; _capacity = n; } // access char& operator[](size_t x)//可读可写 { assert(x < _size); return _arr[x]; } const char& operator[](size_t x)const//可读不可写 { assert(x < _size); return _arr[x]; } //relational operators int judge(const string& s) { return strcmp(_arr, s._arr);//1大于,0等于,-1小于 } bool operator<(const string& s) { int a = judge(s); if (a < 0) return 1; return 0; } bool operator<=(const string& s) { int a = judge(s); if (a > 0) return 0; return 1; } bool operator>(const string& s) { int a = judge(s); if (a > 0) return 1; return 0; } bool operator>=(const string& s) { int a = judge(s); if (a < 0) return 0; return 1; } bool operator==(const string& s) { return !judge(s); } bool operator!=(const string& s) { return judge(s); } // 返回c在string中第一次出现的位置 size_t find(char c, size_t pos = 0) const { assert(pos < _size); while (pos < _size) { if (_arr[pos] == c) return pos; pos++; } return npos; } // 返回子串s在string中第一次出现的位置 size_t find(const char* s, size_t pos = 0) const { assert(pos < _size); const char * p =strstr(_arr + pos, s); if (p == nullptr) { return npos; } else { return p - _arr; } } // 在pos位置上插入字符c/字符串str,并返回该字符的位置 string& insert(size_t pos, char c) { if (_size == _capacity) { size_t len = _size == 0 ? 4 : _capacity * 2;//防止空对象扩容失败 reserve(len); } int end = _size + 1; while (end > pos) { _arr[end] = _arr[end - 1]; end--; } _arr[pos] = c; _size++; return *this; } string& insert(size_t pos, const char* str) { int len = strlen(str); if (_size + len > _capacity) { reserve(_size + len + 1);//不能二倍扩容,万一新加的字符串更大就不行了 } int end1 = _size + 1; int end2 = _size + len; while (end1 > pos) { _arr[end2] = _arr[end1 - 1]; end1--; end2--; } strncpy(_arr + pos, str, len); _size = strlen(_arr); return *this; } // 删除pos位置上的元素,并返回该元素 string& erase(size_t pos, size_t len = npos)//nops是默认值 { if (len == npos || pos + len >= _size)//删除pos后面所有的数据 { _arr[pos] = '\0'; _size = pos; } else { strcpy(_arr + pos, _arr + pos + len); _size -= len; } return *this; } private: char* _arr;//字符串储存的地方 int _size;//大小 int _capacity;//容量 const static size_t npos = -1;//C++只允许整形的静态成员在类的内部进行初始化 }; ostream& operator<<(ostream& out, const string& s)//不一定非要是友元 { for (int i = 0; i < s.size(); i++) { out << s[i]; } return out; } istream& operator >> (istream& in, string& s) { s.clear();//清空原来s中的内容 char buff[128] = { '\0' };//创建一个容纳输入数据的数组 char c = in.get(); int i = 0; while (c != '\n') { if (i == 127) { i = 0; s += buff;//数组满了放入s中,防止s不断扩容 } buff[i++] = c; c = in.get(); } if (i > 0) { buff[i] = '\0'; s += buff; } return in; } }
深浅拷贝与现代写法
这里最重要的是深浅拷贝的现代写法,之前说过类的默认拷贝函数只能实现浅拷贝无法实现深拷贝,需要自定义拷贝函数,类与对象二。
现代写法是让一个新创建的对象帮你拷贝,然后与你进行交换,相当于你有了一个打工人。
string(const string& s)//拷贝构造 :_arr(nullptr)//将被拷贝的对象进行初始化 ,_size(0) ,_capacity(0) { string tmp(s._arr);//打工人tmp swap(tmp);//这里虽然只传参了一个tmp,但是还有一个隐藏的this指针 } string& operator=(string s)//这里不用引用就是临时变量,我们可以让它成为打工人 { swap(s); return *this; } void swap(string& s) { std::swap(_arr, s._arr); std::swap(_size, s._size); std::swap(_capacity, s._capacity); }
之后tmp的成员 _arr指向的就是空指针,进行析构也不会报错,其他成员全都变成0,而需要被拷贝的*this就成功的得到了想要的数据。