> 文档中心 > C++ string类的模拟实现

C++ string类的模拟实现

 目录

 1.string类的结构定义

2.string类迭代器的实现

3.string类的构造,析构,拷贝构造,赋值运算符重载

3.1构造函数

3.2析构函数

3.3拷贝构造函数

3.4赋值运算符重载

4管理字符串的数组,可以增删查改

4.1reverse()接口

4.2resize()接口

4.3push_back接口

4.4append()接口

4.5insert()接口

4.6erase()接口

4.7find()接口

4.8clear()接口

4.9getline()接口

4.10size()接口

4.11c_str()接口

5.运算符重载

5.1[]

5.2==

5.3+=

5.4<

5.5<=

5.6>

 5.7>=

5.8!=

5.9<<

5.10>>

6.补充题目(替换字符串中的空格)


namespace bit{class string{public:typedef char* iterator;public:string(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}string(const string& s): _str(nullptr), _size(0), _capacity(0){string tmp(s._str);this->swap(tmp);}string& operator=(string s){this->Swap(s)return *this;}~string(){if (_str){delete[] _str;_str = nullptr;}}/// iteratoriterator begin() { return _str; }iterator end() { return _str + _size; }/// modifyvoid push_back(char c){if (_size == _capacity)Reserve(_capacity * 2);_str[_size++] = c;_str[_size] = '\0';}string& operator+=(char c){PushBack(c);return *this;}// 作业实现void append(const char* str);string& operator+=(const char* str);void clear(){_size = 0;_str[_size] = '\0';}void swap(string& s){swap(_str, s._str);swap(_size, s._size);swap(_capacity, s._capacity);}const char* c_str()const{return _str;}/// capacitysize_t size()constsize_t capacity()constbool empty()constvoid resize(size_t newSize, char c = '\0'){if (newSize > _size){// 如果newSize大于底层空间大小,则需要重新开辟空间if (newSize > _capacity){Reserve(newSize);}memset(_str + _size, c, newSize - _size);}_size = newSize;_str[newSize] = '\0';}void reserve(size_t newCapacity){// 如果新容量大于旧容量,则开辟空间if (newCapacity > _capacity){char* str = new char[newCapacity + 1];strcpy(str, _str);// 释放原来旧空间,然后使用新空间delete[] _str;_str = str;_capacity = newCapacity;}}// accesschar& operator[](size_t index){assert(index < _size);return _str[index];}const char& operator[](size_t index)const{assert(index < _size);return _str[index];}// 作业bool operator<(const string& s);bool operator(const string& s);bool operator>=(const string& s);bool operator==(const string& s);bool operator!=(const string& s);// 返回c在string中第一次出现的位置size_t find(char c, size_t pos = 0) const;// 返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos = 0) const;// 在pos位置上插入字符c/字符串str,并返回该字符的位置string& insert(size_t pos, char c);string& insert(size_t pos, const char* str);// 删除pos位置上的元素,并返回该元素的下一个位置string& erase(size_t pos, size_t len); private: friend ostream& operator<>(istream& _cin, bit::string& s); private: char* _str; size_t _capacity; size_t _size; };}ostream& bit::operator<<(ostream& _cout, const bit::string& s) {// 不能使用这个//cout << s._str;for (size_t i = 0; i < s.size(); ++i){_cout << s[i];}return _cout;}///对自定义的string类进行测试void TestBitstring(){bit::string s1("hello");s1.push_back(' ');s1.push_back('b');s1.append(1, 'i');s1 += 't';cout << s1 << endl;cout << s1.size() << endl;cout << s1.capacity() << endl;// 利用迭代器打印string中的元素string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;// 这里可以看到一个类只要支持的基本的iterator,就支持范围forfor (auto ch : s1)cout << ch << " ";cout << endl;}

 1.string类的结构定义

 class string{public:private:char* _str;size_t _size;size_t _capacity;static const size_t npos;};

 其中nops就是无符号整型中的-1

2.string类迭代器的实现

 image-20220213131213547

class string{public:    typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}const_iterator begin() const{return _str;}iterator end(){return _str + _size;}const_iterator end() const{return _str + _size;} };

3.string类的构造,析构,拷贝构造,赋值运算符重载

 

class string{public:string(const char* str = ""): _str(new char[strlen(str) + 1]){strcpy(_str, str);}//传统写法string(const string& s):_str(new char[strlen(s._str)+1]){strcpy(_str, s._str);}//赋值重载//s1 = s3//s1 = s1string& operator = (const string& s){if (this != &s)//此处this是s1的地址,防止自己和自己赋值{delete[]_str; _str = new char[strlen(s._str) + 1];strcpy(_str, s._str);}return *this;}//现代写法//s2(s1)string(const string& s):_str(nullptr){string tmp(s._str);swap(_str,tmp._str);}   //赋值//自己和自己赋值时存在缺陷string& operator=(string s){swap(_str, s._str);return *this;}/*string& operator = (contst string& s){if (this != &s){string tmp(s);swap(_str, tmp_str);return *this;}}*/~string(){delete[]_str;_str = nullptr;}const char* c_str(){return _str;}

3.1构造函数

string(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];//给_str一个strlen(s)+1长度的空间strcpy(_str, str);//拷贝}

3.2析构函数

 ~string(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}

3.3拷贝构造函数

swap函数的写法与改进

 

 

// s1.swap(s2);void swap(string& s){    //交换_s和tmp._s,就相当于给this->_s开辟了一块空间,当拷贝函数结束,tmp就会被自动释放::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}//传统写法//s2(s1)string(const string& s):_str(new char[strlen(s._str)+1]){strcpy(_str, s._str);}// s2(s1)  现代写法string(const string& s):_str(nullptr)//必须置空,因为_str开始是个随机数,交换给tmp._str后,释放会引起问题, _size(0), _capacity(0){string tmp(s._str);//直接利用构造函数,给tmp对象开辟了一块空间     /*swap(_str,tmp._str);swap(_size, tmp._size);swap(_capacity, tmp._capacity);*///this->swap(tmp);swap(tmp);}

3.4赋值运算符重载

存在传统和现代两种写法

// s1 = s3 传统写法string& operator=(const string& s){if (this != &s) // s1 = s1//此处this是s1的地址,防止自己和自己赋值{delete[] _str;_str = new char[strlen(s._str) + 1];strcpy(_str, s._str);}return *this;}// s1 = s3 现代写法string& operator=(string s){     /*swap(_str, s._str);swap(_size, s._size);swap(_capacity, s._capacity);*/swap(s);//swap前面已写出return *this;}/*string& operator = (contst string& s){if (this != &s){string tmp(s);swap(_str, tmp_str);return *this;}}*/

4管理字符串的数组,可以增删查改

4.1reverse()接口

// 开空间,扩展capacityvoid reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];//这里必须要多开一个空间存储\0strncpy(tmp, _str, _size + 1);//多开的那个空间存储位置delete[] _str;_str = tmp;_capacity = n;}}

4.2resize()接口

resize( ) 分为三种情况

  • 当n小于size,则size等于n.
  • 当n>size但是小于capacity时,size仍等于n,但是这个时候即使你传入另一个参数ch,也没有用
  • 当n大于size时候,会增容,然后多出的空间会用ch初始化,ch如果不传,就是\0,最后size等于n

// 开空间+初始化,扩展capacity 并且初始化空间。size也要动void resize(size_t n, char val = '\0'){if (n  _capacity){reserve(n);}for (size_t i = _size; i < n; ++i){_str[i] = val;}_str[n] = '\0';_size = n;}}

4.3push_back接口

push_back()针对的是字符

void push_back(char ch){if (_size == _capacity){ //这一步是为了防止_capacity如果为0,开不了空间reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_str[_size + 1] = '\0';//给字符串末尾加\0++_size;//insert(_size, ch);  //或者直接调用insert()}

4.4append()接口

void append(const char* str){/*size_t len = _size + strlen(str);if (len > _capacity){reserve(len);}strcpy(_str + _size, str);_size = len;*///insert(_size, str);}

4.5insert()接口

 插入字符

插入字符串 

 

//插入字符string& insert(size_t pos, char ch){assert(pos = (int)pos){_str[end + 1] = _str[end];--end;}*///或者还可以用指针/*size_t end = _size+1;while (end > pos){_str[end] = _str[end-1];--end;}*/char* end = _str + _size;while (end >= _str + pos){*(end + 1) = *end;--end;}_str[pos] = ch;_size++;return *this;}//在pos位置之前插入字符串string& insert(size_t pos, const char* str){assert(pos  _capacity){reserve(_size + len);}// 挪动数据char* end = _str + _size;while (end >= _str + pos){*(end + len) = *end;--end;}strncpy(_str + pos, str, len);_size += len;return *this;}

4.6erase()接口

从pos位置开始删除len个,如果len不写,末尾删除pos后的全部

 

string& erase(size_t pos, size_t len = npos){assert(pos = leftLen){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;}

4.7find()接口

size_t find(char ch, size_t pos = 0){assert(pos < _size);for (size_t i = pos; i < _size; ++i){if (_str[i] == ch){return i;}}return npos;}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;}else{return npos;}}

4.8clear()接口

void clear(){_size = 0;_str[0] = '\0';}

4.9getline()接口

istream& getline(istream& in, string& s){s.clear();char ch;ch = in.get();while (ch != '\n'){s += ch;ch = in.get();}return in;}

4.10size()接口

size_t size() const//使用size接口,用于遍历{return _size;}

4.11c_str()接口

const char* c_str() const{return _str;}

5.运算符重载

5.1[]

分为支持两个重载,支持读和写,只支持读

// 读const char& operator[](size_t i) const{assert(i < _size);return _str[i];}// 可读,可写char& operator[](size_t i){assert(i < _size);return _str[i];}

5.2==

inline bool operator==(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}

5.3+=

// s1 += 'x'  针对字符string& operator+=(char ch){push_back(ch);return *this;}// s1 += "xxxxx" 针对字符串string& operator+=(const char* str){append(str);return *this;}

5.4<

inline bool operator<(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) < 0;}

5.5<=

inline bool operator<=(const string& s1, const string& s2){return s1 < s2 || s1 == s2;}

5.6>

 inline bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}

 5.7>=

inline bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}

 

5.8!=

inline bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}

 

5.9<<

ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}

 

5.10>>

istream& operator>>(istream& in, string& s){s.clear();char ch;ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;ch = in.get();}return in;}

6.补充题目(替换字符串中的空格)