Ⅵ. operator 运算符重载
0x00 引入
学日期类的时候我们就说过,我们只需实现 < 和 ==,剩下的都可以复用解决。
0x01 operator<
💬 我们在全局实现:
/* s1 < s2*/ bool operator<(const string& s1, const string& s2) { size_t i1 = 0, i2 = 0; while (i1 < s1.size() && i1 < s2.size()) { if (s1[i1] < s2[i2]) { return true; } else if (s1[i1] > s2[i2]) { return false; } else { i1++; i2++; } } return i2 < s2.size() ? true : false; }
当然,我们还可以实现的更简单些,直接用 strcmp 偷个懒:
/* s1 < s2*/ bool operator<(const string& s1, const string& s2) { return strcmp(s1.c_str(), s2.c_str()) < 0; }
0x02 operator=
💬 全局作用域下:
/* s1 == s2 */ bool operator==(const string& s1, const string& s2) { return strcmp(s1.c_str(), s2.c_str()) == 0; }
0x03 剩下的直接复用
💬 operator<=
/* s1 <= s2 */ bool operator<=(const string& s1, const string& s2) { return s1 < s2 || s1 == s2; }
💬 operator>
/* s1 > s2 */ bool operator>(const string& s1, const string& s2) { return !(s1 <= s2); }
💬 operator>=
/* s1 >= s2 */ bool operator>=(const string& s1, const string& s2) { return !(s1 < s2); }
💬 operator!=
/* s1 != s2 */ bool operator!=(const string& s1, const string& s2) { return !(s1 == s2); }
Ⅶ. 流插入和流提取
0x00 引入
我们当时实现日期类的流插入和流提取时,也详细讲过这些,当时讲解了友元。
在友元那一章我们说过 "占参问题" ,这里就不再多做解释了。
如需复习猛戳 👇
【C++要笑着学】友元 | 初始化列表 | 关键字explicit | 静态成员static | 内部类
如果我们重载成成员函数,第一个位置就会被隐含的 this 指针占据。
这样实现出来的流插入必然会不符合我们的使用习惯,所以我们选择在全局实现。
在全局里不存在隐含的 this 指针了。
0x01 operator<< 的实现
💬 operator<<
// cout << s1 → operator<<(cout, s1) 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]; } return out; }
0x02 operator>> 的实现
💬 operator>>
// cin >> istream& operator<<(istream& in, string& s) { char ch = in.get(); while (ch == '\n') { s += ch; ch = in.get(); } return in; }
Ⅷ. 完整代码
#include <iostream> #include <assert.h> using namespace std; namespace chaos { class string { public: /* 构造函数 */ string(const char* str = "") : _size(strlen(str)) // 计算出字符串str的大小 , _capacity(_size) { // 初始容量等于字符串大小 _str = new char[_capacity + 1]; // 开辟一块 "容量+1" 大小的空间 (_capacity存的是有效字符) strcpy(_str, str); // 将传入的字符串str复制到 _str中 } void Swap(string& tmp) { swap(_str, tmp._str); swap(_size, tmp._size); swap(_capacity, tmp._capacity); } /* 拷贝构造函数:s2(s1) string(const string& src) : _size(src._size) // 拷贝string大小 , _capacity(src._capacity) { // 拷贝string容量 // 拷贝string内容 _str = new char[src._capacity + 1]; // 开辟一块和src相同容量的空间 strcpy(_str, src._str); // 将src中的_str内容拷贝到自己的_str中 } */ string(const string& src) : _str(nullptr) , _size(0) , _capacity(0) { string tmp(src._str); // 拷贝构造一个src Swap(tmp); // 现代写法:交换 } /* 赋值重载:s1 = s3 string& operator=(const string& src) { // 防止自己跟自己赋值 if (this != &src) { // 1. 暂时用tmp开辟一块相同的空间 char* tmp = new char[src._capacity + 1]; // 2. 把src的值复制给tmp strcpy(tmp, src._str); // 3. 释放this原空间 delete[] _str; // 4. 没翻车,把tmp交付给_src _str = tmp; _size = src._size; _capacity = src._capacity; } return *this; } string& operator=(const string& src) { // 防止自己跟自己赋值 if (this != &src) { string tmp(src); // 复用拷贝构造 Swap(tmp); } return *this; } */ string& operator=(string src) { Swap(src); // 正好调用拷贝构造,不如让形参充当tmp return *this; } /* 返回C格式的字符串:c_str */ const char* c_str() const { return _str; } /* 求字符串大小:size() */ size_t size() const { return _size; } /* operator[] */ char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; // 返回字符串对应下标位置的元素 } const char& operator[](size_t pos) const { assert(pos < _size); return _str[pos]; } /* 迭代器 */ typedef char* iterator; iterator begin() { return _str; // 返回第一个字符的位置 } iterator end() { return _str + _size; // 返回最后一个字符的位置 } /* const迭代器 */ typedef const char* const_iterator; const_iterator begin() const { return _str; } const_iterator end() const { return _str + _size; } /* reserve() */ void reserve(size_t new_capacity) { if (new_capacity > _capacity) { // 检查是否真的需要扩容 char* tmp = new char[new_capacity + 1]; // 开空间 strcpy(tmp, _str); // 先搬运数据到tmp _str = tmp; // 没翻车,递交给_str _capacity = new_capacity; // 更新容量 } } /* 字符尾插:push_back() */ void push_back(char append_ch) { /* if (_size == _capacity) { // 检查是否需要扩容 reserve(_capacity == 0 ? 4 : _capacity * 2); // 首次给4,其他情况默认扩2倍 } _str[_size] = append_ch; // 插入要追加的字符 _size++; _str[_size] = '\0'; // 手动添加'\0' */ insert(_size, append_ch); } /* 字符串追加:append() */ void append(const char* append_str) { /* size_t len = strlen(append_str); // 计算出要追加的字符串的长度 if (_size + len > _capacity) { // 检查是否需要扩容 reserve(_size + len); } strcpy(_str + _size, append_str); // 首字符+大小,就是'\0'位置 _size += len; // 更新大小 */ insert(_size, append_str); } /* operator+= */ string& operator+=(char append_ch) { push_back(append_ch); return *this; } string& operator+=(const char* append_str) { append(append_str); return *this; } /* insert */ string& insert(size_t pos, char append_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] = append_ch; _size++; return *this; } string& insert(size_t pos, const char* append_str) { assert(pos <= _size); size_t len = strlen(append_str); if (_size + len > _capacity) { // 检查是否需要增容 reserve(_size + len); } // 向后挪动数据 size_t end = _size + len; while (end > pos + len - 1) { _str[end] = _str[end - len]; end--; } // 插入 strncpy(_str + pos, append_str, len); _size += len; return *this; } /* resize */ void resize(size_t new_capacity, char init_ch = '\0') { // 如果欲增容量比_size小 if (new_capacity <= _size) { _str[new_capacity] = '\0'; // 拿斜杠零去截断 _size = new_capacity; // 更新大小 } // 欲增容量比_size大 else { if (new_capacity > _capacity) { reserve(new_capacity); } // 起始位置,初始化字符,初始化个数 memset(_str + _size, init_ch, new_capacity - _size); _size = _capacity; _str[_size] = '\0'; } } /* find */ size_t find(char aim_ch) { for (size_t i = 0; i < _size; i++) { if (aim_ch == _str[i]) { // 找到了 return i; // 返回下标 } } // 找不到 return npos; } size_t find(const char* aim_str, size_t pos = 0) { const char* ptr = strstr(_str + pos, aim_str); if (ptr == nullptr) { return npos; } else { return ptr - _str; // 减开头 } } /* 删除:erase */ string& erase(size_t pos, size_t len = npos) { assert(pos < _size); if (len == pos || pos + len >= _size) { _str[pos] = '\0'; // 放置\0截断 _size = pos; } else { strcpy(_str + pos, _str + pos + len); _size -= len; } return *this; } /* 析构函数 */ ~string() { if (_str != nullptr) { delete[] _str; _str = nullptr; } _size = _capacity = 0; } private: /* 成员变量 */ char* _str; size_t _size; size_t _capacity; public: static const size_t npos; }; /* 初始化npos */ const size_t string::npos = -1; // 无符号整型的-1,即整型最大值 /* s1 < s2*/ bool operator<(const string& s1, const string& s2) { /* size_t i1 = 0, i2 = 0; while (i1 < s1.size() && i1 < s2.size()) { if (s1[i1] < s2[i2]) { return true; } else if (s1[i1] > s2[i2]) { return false; } else { i1++; i2++; } } return i2 < s2.size() ? true : false; */ return strcmp(s1.c_str(), s2.c_str()) < 0; } /* s1 == s2 */ bool operator==(const string& s1, const string& s2) { return strcmp(s1.c_str(), s2.c_str()) == 0; } /* s1 <= s2 */ bool operator<=(const string& s1, const string& s2) { return s1 < s2 || s1 == s2; } /* s1 > s2 */ bool operator>(const string& s1, const string& s2) { return !(s1 <= s2); } /* s1 >= s2 */ bool operator>=(const string& s1, const string& s2) { return !(s1 < s2); } /* s1 != s2 */ bool operator!=(const string& s1, const string& s2) { return !(s1 == s2); } // cout << s1 → operator<<(cout, s1) 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]; } return out; } // cin >> istream& operator<<(istream& in, string& s) { char ch = in.get(); while (ch == '\n') { s += ch; ch = in.get(); } return in; } /* 测试用 */ void test_string1() { string s1("hello world"); string s2(s1); cout << s1.c_str() << endl; cout << s2.c_str() << endl; string s3("pig"); cout << s3.c_str() << endl; s1 = s3; cout << s1.c_str() << endl; } void test_string2() { string s1("hello world"); string s2; for (size_t i = 0; i < s1.size(); i++) { cout << s1[i] << " "; } cout << endl; } void test_string3() { string s1("hello world"); string s2; s1[0] = 'F'; for (size_t i = 0; i < s1.size(); i++) { cout << s1[i] << " "; } cout << endl; } void test_string4() { string s1("hello world"); // 迭代器写 string::iterator it = s1.begin(); while (it != s1.end()) { *it += 1; it++; } // 迭代器读 it = s1.begin(); // 重置起点 while (it != s1.end()) { cout << *it << " "; it++; } } void test_string5() { string s1("hello world"); cout << s1.c_str() << endl; s1.push_back('!'); cout << s1.c_str() << endl; s1.push_back('A'); cout << s1.c_str() << endl; } void test_string6() { string s1("hello world"); cout << s1.c_str() << endl; s1 += '!'; cout << s1.c_str() << endl; s1 += "this is new data"; cout << s1.c_str() << endl; } void test_string7() { string s1("hello world"); cout << s1.c_str() << endl; s1.insert(0, 'X'); cout << s1.c_str() << endl; s1.insert(0, "hahahaha"); cout << s1.c_str() << endl; } void test_string8() { string s1("hello world"); cout << s1.c_str() << endl; s1.erase(5, 2); // 从第五个位置开始,删两个字符 cout << s1.c_str() << endl; s1.erase(5, 20); // 从第五个位置开始,删完 cout << s1.c_str() << endl; } }