C++模拟实现string类的实例代码
更新时间:2023年08月13日 14:21:11 作者:派小星233
这篇文章主要给大家介绍了C++如何模拟实现string类,文章通过代码示例讲解的非常详细,有完整的实现过程,具有一定的参考价值,需要的朋友可以参考下
成员变量
public: //类外可能要访问,设计成公有 static const size_t npos; private: //指向实际存储字符串的空间 char* _str; //记录容量 size_t _capacity; //记录有效字符,'\0'不算 size_t _size; //记得类外定义静态变量 const size_t string::npos = -1;
构造和析构
string(const char* str = "") :_capacity(strlen(str)) ,_size(_capacity) { _str = new char[_capacity + 1]; strcpy(_str, str); } string(const string& s) :_capacity(s._capacity) ,_size(s._size) { _str = new char[_capacity + 1]; strcpy(_str, s._str); } ~string() { delete[] _str; _str = nullptr; _size = _capacity = 0; }
容量相关
1.获取容器大小(_size)和容量(_capacity)
//加const修饰this指针,因为const修饰对象也需要调用这几个接口 size_t size()const { return _size; } size_t capacity()const { return _capacity; } bool empty()const { //为空返回true,为假返回false return (_size == 0); }
2.扩容(reserve)
void reserve(size_t n) { //只有n大于容量才进行扩容 if (n > _capacity) { //重新开一片空间,拷贝完成后释放原空间 //修改指针指向,更改容量 char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } }
3.更改容器大小
//设计成半缺省 void resize(size_t n, char c = '\0') { //n > _size,扩容后用c填满容器 if (n > _size) { reserve(n); for (size_t i = _size; i < _capacity; i++) { _str[i] = c; } _str[_capacity] = '\0'; _size = _capacity; } else { //n <= _size的情况,直接把下标n的位置改为'\0',修改_size即可 _str[n] = '\0'; _size = n; } }
修改相关
1.尾插
//尾部插入一个字符 void push_back(char c) { //先判断是否扩容 if (_size == _capacity) reserve(_capacity == 0 ? 4 : _capacity * 2); //把原'\0'位置修改为新字符,记得补'\0' _str[_size] = c; _str[_size + 1] = '\0'; _size++; } //+=复用即可 string& operator+=(char c) { push_back(c); return (*this); } //尾部插入字符串 void append(const char* str) { size_t len = strlen(str); //先判断是否扩容 if (len + _size > _capacity) reserve(len + _size); //从原'\0'位置开始拷贝 strcpy(_str + _size, str); //更新_size _size += len; } string& operator+=(const char* str) { //+=复用即可 append(str); return (*this); }
2.指定位置插入
// 在pos位置上插入字符c string& insert(size_t pos, char c) { //断言,不然可能越界 assert(pos <= _size); if (_size == _capacity) reserve(2 * _capacity); //pos位置后字符后移一位 for (int i = _size; i >= (int)pos; i--) _str[i + 1] = _str[i]; _str[pos] = c; _size++; return (*this); } //在pos位置上插入字符串str string& insert(size_t pos, const char* str) { //断言,不然可能越界 assert(pos <= _size); size_t len = strlen(str); if ((_size + len) > _capacity) reserve(_size + len); for (int i = _size; i >= (int)pos; i--) { _str[i + len] = _str[i]; } for (int i = 0; i < len; i++) { _str[pos++] = str[i]; } _size += len; return (*this); }
3.指定位置删除
// 删除pos位置上的元素 string& erase(size_t pos, size_t len = npos) { assert(pos <= _size); //要删除的字符数大于后面字符,就把pos位置和后面全部删除完 if (len == npos || pos + len >= _size) { _size = pos; _str[_size] = '\0'; } else { for (size_t i = pos; i <= pos + _size - len; i++) { _str[i] = _str[i + len]; } _size -= len; } return (*this); }
4.清空
void clear() { _str[0] = '\0'; _size = 0; }
5.交换两个对象
void swap(string& s) { std::swap(_str, s._str); std::swap(_capacity, s._capacity); std::swap(_size, s._size); }
比较相关
//写好< 和 == ,其它复用即可 bool operator<(const string& s)const { return strcmp(_str, s._str) < 0; } bool operator<=(const string& s)const { return (*this) < s || (*this) == s; } bool operator>(const string& s)const { return !((*this) <= s); } bool operator>=(const string& s)const { return !((*this) < s); } bool operator==(const string& s)const { return strcmp(_str, s._str) == 0; } bool operator!=(const string& s)const { return !((*this == s)); }
访问相关
char& operator[](size_t index) { assert(index <= _size); return _str[index]; } //函数重载,这个版本专门给const用 const char& operator[](size_t index)const { assert(index <= _size); return _str[index]; }
迭代器相关
//string的迭代器底层是指针 typedef char* iterator; typedef const char* const_iterator; iterator begin() { return _str; } iterator end() { return (_str + _size); } const_iterator begin()const { return _str; } const_iterator end()const { return (_str + _size); }
查找相关
// 查找字符,返回c在string中第一次出现的位置 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; } //查找子串,返回子串s在string中第一次出现的位置 size_t find(const char* s, size_t pos = 0) const { //断言,不然可能越界 assert(pos < _size); //直接调用库函数找到子串位置 const char* p = strstr(_str + pos, s); if (p) return p - _str;//指针相减得到指针间元素数量,刚好为下标 else return npos; }
其它成员函数
1.截取子串
string substr(size_t pos, size_t len = npos) { assert(pos < _size); string s; size_t end = pos + len; //如果len大于后面所剩的字符,就把后面全部截取 if (len == npos || end >= _size) { len = _size - pos; end = _size; } s.reserve(len); for (size_t i = pos; i < end; i++) { s += _str[i]; } return s; }
2.取得C格式字符串
const char* c_str()const { return _str; }
3.赋值
//这里使用传值传参,编译器自行完成拷贝,交换两者即可 string& operator=(string s) { swap(s); return (*this); }
非成员函数
ostream& operator<<(ostream& _cout, const string& s) { _cout << s.c_str() << endl; return _cout; } istream& operator>>(istream& _cin, string& s) { s.clear(); //避免多次扩容,以128为一组进行写入 char tmp[128] = ""; int i = 0; char ch = '0'; ch = _cin.get(); while (ch != ' ' && ch != '\n') { tmp[i++] = ch; if (i == 127) { tmp[i] = '\0'; s += tmp; i = 0; } ch = _cin.get(); } if (i != 0) { tmp[i] = '\0'; s += tmp; } return _cin; }
完整代码
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string.h> #include<assert.h> using namespace std; namespace MyStd { class string { public: typedef char* iterator; typedef const char* const_iterator; string(const char* str = "") :_capacity(strlen(str)) ,_size(_capacity) { _str = new char[_capacity + 1]; strcpy(_str, str); } string(const string& s) :_capacity(s._capacity) ,_size(s._size) { _str = new char[_capacity + 1]; strcpy(_str, s._str); } string& operator=(string s) { swap(s); return (*this); } ~string() { delete[] _str; _str = nullptr; _size = _capacity = 0; } // // iterator iterator begin() { return _str; } iterator end() { return (_str + _size); } const_iterator begin()const { return _str; } const_iterator end()const { return (_str + _size); } // modify //尾部插入一个字符 void push_back(char c) { //先判断是否扩容 if (_size == _capacity) reserve(_capacity == 0 ? 4 : _capacity * 2); //把原'\0'位置修改为新字符,记得补'\0' _str[_size] = c; _str[_size + 1] = '\0'; _size++; } //+=复用即可 string& operator+=(char c) { push_back(c); return (*this); } //尾部插入字符串 void append(const char* str) { size_t len = strlen(str); //先判断是否扩容 if (len + _size > _capacity) reserve(len + _size); //从原'\0'位置开始拷贝 strcpy(_str + _size, str); //更新_size _size += len; } string& operator+=(const char* str) { //+=复用即可 append(str); return (*this); } void clear() { _str[0] = '\0'; _size = 0; } void swap(string& s) { std::swap(_str, s._str); std::swap(_capacity, s._capacity); std::swap(_size, s._size); } const char* c_str()const { return _str; } / // capacity //加const修饰this指针,因为const修饰对象也需要调用这几个接口 size_t size()const { return _size; } size_t capacity()const { return _capacity; } bool empty()const { //为空返回true,为假返回false return (_size == 0); } //设计成半缺省 void resize(size_t n, char c = '\0') { //n > _size,扩容后用c填满容器 if (n > _size) { reserve(n); for (size_t i = _size; i < _capacity; i++) { _str[i] = c; } _str[_capacity] = '\0'; _size = _capacity; } else { //n <= _size的情况,直接把下标n的位置改为'\0',修改_size即可 _str[n] = '\0'; _size = n; } } void reserve(size_t n) { //只有n大于容量才进行扩容 if (n > _capacity) { //重新开一片空间,拷贝完成后释放原空间 //修改指针指向,更改容量 char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } / // access char& operator[](size_t index) { assert(index <= _size); return _str[index]; } const char& operator[](size_t index)const { assert(index <= _size); return _str[index]; } / //relational operators //写好< 和 == ,其它复用即可 bool operator<(const string& s)const { return strcmp(_str, s._str) < 0; } bool operator<=(const string& s)const { return (*this) < s || (*this) == s; } bool operator>(const string& s)const { return !((*this) <= s); } bool operator>=(const string& s)const { return !((*this) < s); } bool operator==(const string& s)const { return strcmp(_str, s._str) == 0; } bool operator!=(const string& s)const { return !((*this == s)); } // 查找字符,返回c在string中第一次出现的位置 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; } //查找子串,返回子串s在string中第一次出现的位置 size_t find(const char* s, size_t pos = 0) const { //断言,不然可能越界 assert(pos < _size); //直接调用库函数找到子串位置 const char* p = strstr(_str + pos, s); if (p) return p - _str;//指针相减得到指针间元素数量,刚好为下标 else return npos; } string substr(size_t pos, size_t len = npos) { assert(pos < _size); string s; size_t end = pos + len; //如果len大于后面所剩的字符,就把后面全部截取 if (len == npos || end >= _size) { len = _size - pos; end = _size; } s.reserve(len); for (size_t i = pos; i < end; i++) { s += _str[i]; } return s; } // 在pos位置上插入字符c string& insert(size_t pos, char c) { //断言,不然可能越界 assert(pos <= _size); if (_size == _capacity) reserve(2 * _capacity); //pos位置后字符后移一位 for (int i = _size; i >= (int)pos; i--) _str[i + 1] = _str[i]; _str[pos] = c; _size++; return (*this); } //在pos位置上插入字符串str string& insert(size_t pos, const char* str) { //断言,不然可能越界 assert(pos <= _size); size_t len = strlen(str); if ((_size + len) > _capacity) reserve(_size + len); for (int i = _size; i >= (int)pos; i--) { _str[i + len] = _str[i]; } for (int i = 0; i < len; i++) { _str[pos++] = str[i]; } _size += len; return (*this); } // 删除pos位置上的元素 string& erase(size_t pos, size_t len = npos) { assert(pos <= _size); //要删除的字符数大于后面字符,就把pos位置和后面全部删除完 if (len == npos || pos + len >= _size) { _size = pos; _str[_size] = '\0'; } else { for (size_t i = pos; i <= pos + _size - len; i++) { _str[i] = _str[i + len]; } _size -= len; } return (*this); } public: //类外可能要访问,设计成公用 static const size_t npos; private: //指向实际存储字符串的空间 char* _str; //记录容量 size_t _capacity; //记录有效字符,'\0'不算 size_t _size; }; ostream& operator<<(ostream& _cout, const string& s) { _cout << s.c_str() << endl; return _cout; } istream& operator>>(istream& _cin, string& s) { s.clear(); //避免多次扩容 char tmp[128] = ""; int i = 0; char ch = '0'; ch = _cin.get(); while (ch != ' ' && ch != '\n') { tmp[i++] = ch; if (i == 127) { tmp[i] = '\0'; s += tmp; i = 0; } ch = _cin.get(); } if (i != 0) { tmp[i] = '\0'; s += tmp; } return _cin; } //静态成员在外部定义 const size_t string::npos = -1; };
以上就是C++模拟实现string类的实例代码的详细内容,更多关于C++模拟实现string类的资料请关注脚本之家其它相关文章!
相关文章
Windows下使用Dev-C++开发基于pthread.h的多线程程序实例
下面小编就为大家带来一篇Windows下使用Dev-C++开发基于pthread.h的多线程程序实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧2017-09-09JetBrains CLion永久激活超详细教程(最新激活方法)
JetBrains Clion 是一款专为 C/C++ 开发所设计的跨平台 IDE,本文适用 JetBrains CLion v2019.3/3.1/3.2/3.3 永久激活,附破解补丁和激活码,可以永久激活 Windows、MAC、Linux 下的 CLion,下面给大家分享JetBrains CLion永久激活超详细教程,感兴趣的朋友一起看看吧2023-01-01
最新评论