string的模拟实现,模拟实现包括string类的构造、拷贝构造、赋值运算符重载、析构、迭代器、swap、operator[ ]、size()、c_str()、reserve() 、resize()、push_back()、append()、operator+=()、insert()、erase()、find()、operator>、operator==、operator>=、operator<、operator<=、operator!=、clear()、operator<<、operator>>函数
#pragma once #define _CRT_SECURE_NO_WARNINGS #include#include #include using namespace std; //定义一个新的命名空间,和全局命名空间隔离开 namespace delia { class string { public: typedef char* iterator; //迭代器 iterator begin() { return _str; } //迭代器 iterator end() { return _str + _size; } //const迭代器 iterator begin() const { return _str; } //const迭代器 iterator end() const { return _str + _size; } //构造函数 string(const char* str = "") { _str = new char[strlen(str) + 1];//1是留给'/0'的,_size最大为申请字节数-1,_capacity也为申请字节数-1 strcpy(_str, str); _size = strlen(str); _capacity = _size; } //现代拷贝构造 string(const string& s) :_str(nullptr) , _size(0) , _capacity(0) { string tmp(s._str); swap(tmp); } //赋值运算符重载 string& operator=(string s) { swap(s); return *this; } //析构函数 ~string() { delete[] _str; _str = nullptr; _size = 0; _capacity = 0; } //实现交换函数 void swap(string& s) { ::swap(_str, s._str);//用::指定调用全局的swap函数即库里的swap函数 ::swap(_size, s._size); ::swap(_capacity, s._capacity); } //const string对象遍历,只读 char& operator[](size_t i) const//char要加&,如果不加,那么return就是传值返回,返回的是_str[i]的拷贝,临时对象,而临时对象具有常性,不能被修改,只能读 //如果要对_str进行修改的话,char要加&,用传引用返回 { assert(i < _size); return _str[i]; } //非const string对象遍历,可读可写 char& operator[](size_t i) { assert(i < _size); return _str[i]; } //求string对象大小 size_t size() const { return strlen(_str); } //获取c形式字符串,将 const string* 类型 转化为 const char* 类型 const char* c_str() { return _str; } //开空间,扩展_capacity,_size不变 void reserve(size_t n) { //1.申请新空间 //2.拷贝字符串 //3.释放旧空间 //4.指向新空间 //5.更新容量 if (n > _capacity) { char* tmp = new char[n + 1];//1.申请新空间,多开的那一个空间,存放 strncpy(tmp, _str, _size + 1);//2.将字符串包含 在内都拷贝到新空间 delete[] _str;//3.释放旧空间 _str = tmp;//4.指向新空间 _capacity = n;//5.更新容量 } } //开空间+初始化,扩展_capacity,_size也要修改 void resize(size_t n, char val = ' ')//如果没有显式给出val,val为 { //1.当n<_size,无需增容 if (n < _size) { _size = n;//直接更新_size _str[_size] = ' ';//将_size位置置为 } //2.当n>_size,分两种情况 //(1)_size < n <_capacity,无需增容,直接将_size到n位置置为val //(2)n >_capacity,需增容,并将_size到n位置置为val //这两种情况只有是否增容的区别,其他没有区别 else { if (n > _capacity) { reserve(n); } for (size_t i = _size; i < n; i++) { _str[i] = val; } _str[n] = ' ';//将n的位置置 _size = n;//更新_size } } //尾插一个字符 void push_back(char ch) { //字符个数已经达到容量时,重新开空间 if (_size == _capacity) { reserve(_capacity == 0 ? 4 : _capacity * 2);//如果是第一次开空间,就开4个字节,如果不是第一次开空间,就开成原来的2倍容量 } _str[_size] = ch;//将字符ch缀到字符串末尾 _str[_size + 1] = ' ';//字符ch后面加 ,表明字符串结束 _size++;//字符串大小+1 } //追加字符串 void append(const char* str) { size_t len = _size + strlen(str);//函数执行完毕后字符串的大小 if (len > _capacity) { reserve(len);//空间不够,增容 } strcpy(_str + _size, str);//将str内容拷贝至_str末尾 _size = len;//更新_size } //+= 1个字符 string& operator+= (char c) { push_back(c);//尾插字符 return *this; } //+= 字符串 string& operator+= (const char* str) { append(str);//拼接字符串 return *this; } //insert插入一个字符 string& insert(size_t pos, const char ch) { assert(pos <= _size);//pos必须小于等于字符串长度 if (_size == _capacity) { reserve(2 * _capacity);//如果满了就增容 } size_t end = _size + 1; while (end > pos)//将pos至_size之间的字符依次向后挪动一个位置,来腾出pos位置 { _str[end] = _str[end - 1]; end--;//end为0时,因此end类型应为int,那么end--就为-1,pos为无符号数,不满足循环条件,退出循环 //但如果end类型为size_t,那么end为0时,end--就为-1,在内存中存储为无符号数(-1补码全1),满足循环条件,永远无法退出循环 } _str[pos] = ch;//pos位置插入ch _size++;//更新_size return *this; } //erase 删除字符 string& erase(size_t pos, size_t len = npos) { assert(pos < _size); size_t leftLen = _size - pos;//从pos位置到字符串结束的字符长度 if (leftLen < len)//1.pos之后的字符全部删掉 { _str[pos] = ' '; _size = pos; } else//2.pos之后的字符删掉一部分,没删完的部分要挪到pos位置 { strcpy(_str + pos, _str + pos + len); _size -= len; } return *this; } //查找字符 size_t find(char ch, size_t pos = 0) { assert(pos < _size); for (size_t i = 0; i < _size; i++) { if (_str[i] == ch) { return i;//找到就返回字符所在位置 } } return npos;//没找到就返回-1 } //查找字符串(子串) size_t find(const char* str, size_t pos = 0) { assert(pos < _size); const char* ret = strstr(_str + pos, str); if (ret) { return ret - _str;//计算str与_str的偏移量,即str在_str中的下标 } else { return npos;//没找到就返回-1 } } //字符串比较,只需要实现>和== bool operator>(const string& s) { return strcmp(_str, s._str) < 0; } bool operator==(const string& s) { return strcmp(_str, s._str) == 0; } // 其它4个运算符都可以对>和==这两个运算符进行重载 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); } void clear() { _size = 0; _str[0] = ' '; } private: char* _str; size_t _size; size_t _capacity; static const size_t npos; }; const size_t string::npos = -1;//npos初始化 //输出重载<<让string直接输出打印,像内置类型一样,用范围for就可以实现 ostream& operator<<(ostream& out, const string& s) { for (auto ch: s) { out << s; } return out; } //输入重载>>让string直接输入,像内置类型一样;从标准输入流读取字符,遇到' '或' '就停止 istream& operator>>(istream& in, string& s) { s.clear(); char ch; ch = in.get(); while (ch != ' ' && ch != ' ') { s += ch; ch = in.get(); } return in; } void f(const string& s) { for (size_t i = 0; i < s.size(); i++) { cout << s[i] << " "; } cout << endl; } void test_string1() { string s1("hello world"); string s2(s1); string s3("cplusplus.com"); std::swap(s1, s3);//调用库里的swap函数,3次深拷贝,再把原来的空间释放掉,再开一样大的空间,代价大 s1.swap(s3);//调用delia::string类里面的成员函数swap,仅仅只是成员变量的交换,s3指向了s1的空间,s1指向了s3的空间 string s4 = s1.c_str(); s1[2] = 'w'; f(s1);//h e w l o w o r l d for (size_t i = 0; i < s1.size(); i++) { cout << s1[i] << " "; } cout << endl;//h e w l o w o r l d } void test_string2() { string s1("hello world"); //使用迭代器遍历 string::iterator it = s1.begin(); while (it != s1.end()) { cout << *it << " "; it++; } cout << endl;//h e l l o w o r l d //使用范围for遍历,范围for会被编译器替换成迭代器形式,如果把17-26行屏蔽,会发现编译不过 for (auto ch : s1) { cout << *it << " "; } cout << endl;//h e l l o w o r l d } void test_string3() { string s1("hello world"); s1 += "abc"; for (auto& ch : s1) { cout << ch << " "; } cout << endl;//h e l l o w o r l d a b c s1 += "xyz"; for (auto& ch : s1) { cout << ch << " "; } cout << endl;//h e l l o w o r l d a b c x y z } void test_string4() { string s1("hello world"); s1 += '#'; for (auto ch : s1) { cout << ch << " "; } cout << endl;//hello world# s1 += "xyz"; for (auto ch : s1) { cout << ch << " "; } cout << endl;//hello world#xyz s1 += "!!!!!!!!!!!!!!!!!!!!"; for (auto ch : s1) { cout << ch << " "; } cout << endl;//hello world#xyz!!!!!!!!!!!!!!!!!!!! } void test_string5() { string s1("hello world"); s1.resize(3); cout << s1.c_str() << endl;//hel } void test_string6() { string s1("hello"); s1.resize(6, 'a'); cout << s1.c_str() << endl;//helloa } void test_string7() { string s1("hello"); s1.resize(9, 'o'); cout << s1.c_str() << endl;//helloooo } void test_string8() { string s1("hello"); s1.insert(0, 'u'); cout << s1.c_str() << endl;//uhello } void test_string9() { string s1("hello"); s1.erase(0, 2); cout << s1.c_str() << endl;//llo string s2("world"); s2.erase(1);//如果不给len,那么npos=-1,无符号数为4294967295,删除从位置为1-4294967295的字符,把后面的字符全部删除了 cout << s2.c_str() << endl;//w } void test_string10() { string s1("hello world"); cout << s1.find("rl",6) << endl;//8,从s1中的第6个位置开始查找"rl"字符串 } void test_string11() { std::string s("hello"); cin >> s; cout << s << endl; } } int main() { //delia::test_string1(); //delia::test_string2(); //delia::test_string3(); //delia::test_string4(); //delia::test_string5(); //delia::test_string6(); //delia::test_string7(); //delia::test_string8(); //delia::test_string9(); //delia::test_string10(); delia::test_string11(); return 0; }



