当前位置:   article > 正文

【C++】——string模拟实现

【C++】——string模拟实现

前言

string的模拟实现其实就是增删改查,只不过加入了类的概念。

为了防止与std里面的string冲突,所以这里统一用String。

目录

前言

一   初始化和销毁 

1.1  构造函数

1.2  析构函数

 二  迭代器实现

三  容量大小及操作

 四 运算符重载

 4.1  bool operator<(const String& s) const

4.2  bool operator==(const String& s) const 

 4.3  bool operator<=(const String& s) const

4.4 bool operator>(const String& s) const

4.5  bool operator>=(const String& s) const 

 4.6  bool operator!=(const String& s) const

 五  字符串操作 

5.1  截取操作

5.2  查找操作

六  流插入流提取

6.1  ostream& operator<<(ostream& out, const String& s)

6.2   istream& operator>>(istream& in, String& s)

 七  string与string相加

String operator+(const String& s2)

string类模拟实现完整代码

总结


一   初始化和销毁 

1.1  构造函数

对于构造函数来说有有参构造和无参构造

所以直接把他们结合起来

default 
string();
copy 
string (const string& str);

 1.string();//无参构造

2.string (const string& str);//有参构造

  1. String(const char* str = "") :_size(strlen(str)), _capacity(_size)
  2. {
  3. _str = new char[_capacity+1];
  4. strcpy(_str, str);
  5. }

 如果把_str的初始化放在初始化列表会出问题

  1. private:
  2. char* _str;
  3. size_t _size;
  4. size_t _capacity;
  5. static const size_t npos = -1;
  1. String(const char* str = "") :_str(new char [_capacity+1]),_size(strlen(str)), _capacity(_size)
  2. {
  3. //_str = new char[_capacity+1];
  4. strcpy(_str, str);
  5. }

初始化列表是会按照成员变量的顺序去初始化,所以这里 初始化_str,_capacity没有初始化,所以在开空间的时候会出问题,当然你可以换一换位置,但是未免太繁琐,同时这里不能把_str设置为nullptr,如果设置为空,那么_size正初始化就会出问题

1.2  析构函数

 这里的析构函数没有那么多细节,直接释放空间,然后处理其他的成员变量就行了

  1. ~String()
  2. {
  3. delete[] _str;//注意这里的delete[],不是delete
  4. _str = nullptr;
  5. _size = 0;
  6. _capacity = 0;
  7. }

 二  迭代器实现

其实迭代器可以理解为是指针在进行,有的底层是指针有的是其他的方法,这里我们用指针去模拟实现

  1. //迭代器
  2. typedef char* iterator;
  3. typedef char* const_iterator;
  4. iterator begin()
  5. {
  6. return _str;
  7. }
  8. iterator end()
  9. {
  10. return _str + _size;
  11. }
  12. const_iterator begin()const
  13. {
  14. return _str;
  15. }
  16. const_iterator end()const
  17. {
  18. return _str + _size;
  19. }

迭代器也需要const类型,这样const类型的函数才能去调用,所以写两份。注意范围for就是无脑替换迭代器,本质和迭代器是一样的。

测试案例

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"String.h"
  3. int main()
  4. {
  5. String str("Test string");
  6. for (String::iterator it = str.begin(); it != str.end(); ++it)
  7. cout << *it;
  8. cout << '\n';
  9. for (auto ch : str)
  10. {
  11. cout << ch << " ";
  12. }
  13. cout << endl;
  14. return 0;
  15. }

还有反向迭代器,这里就不一一列举了,想了解的可以参考string类的介绍

三  容量大小及操作

1.capacity()//表示容量大小

2.size()//有效数据大小

3.max_size()//最大有多少数据

4.empty()//是否为空

5.resize()//扩容

6.reserve()//扩容

  1. size_t size()const
  2. {
  3. return _size;
  4. }
  5. size_t capacity()const
  6. {
  7. return _capacity;
  8. }
  9. size_t max_size()const
  10. {
  11. return 4294967291;
  12. }
  13. bool empty()const
  14. {
  15. return _size == 0;
  16. }
  17. void reserve(size_t n)
  18. {
  19. if (n > _capacity)
  20. {
  21. char* tmp = new char[n + 1];
  22. strcpy(tmp, _str);
  23. delete[]_str;
  24. _str = tmp;
  25. }
  26. _capacity = n;
  27. }
  28. void resize(size_t n, char ch = '\0')
  29. {
  30. if (n < _size)
  31. {
  32. _str[n] = '\n';
  33. _size = n;
  34. }
  35. else
  36. {
  37. reserve(n);
  38. while (_size < n)
  39. {
  40. _str[_size] = ch;
  41. _size++;
  42. }
  43. _str[_size] = '\0';
  44. }
  45. }

1.对于empty,它是如果为空,才是真,不为空就假

2.对于resize和reserve来说,从参数列表可以看出,resize可以设置初始值,也就是可以改变_size,

但是reserve不行,同时reserve设置的n如果比capacity小的话,是不会造成任何影响或者改变的

3.这里的max_size,这里我设置了一个常量,但是并没有这么简单,因为max_size是根据你当前系统来判断该给多大的,因素很多,但是实现起来很麻烦,这里就简单的设置为初始值了

测试案例

由于其他的测试在之前的string类博客测试过了,所以这里就不一一测试了

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"String.h"
  3. int main()
  4. {
  5. String str("Test string");
  6. cout << "size: " << str.size() << "\n";
  7. cout << "capacity: " << str.capacity() << "\n";
  8. cout << "max_size: " << str.max_size() << "\n";
  9. return 0;
  10. }

 四 运算符重载

 运算符重载就是>,<,=,>=,<=这四种,但是其实写一个大于和等于或者写一个小于和等于就行了,因为其他的都能复用

 4.1  bool operator<(const String& s) const
  1. bool operator<(const String& s) const
  2. {
  3. return strcmp(_str, s._str) < 0;
  4. }

4.2  bool operator==(const String& s) const 
  1. bool operator==(const String& s) const
  2. {
  3. return strcmp(_str, s._str) == 0;
  4. }

由于上面写了<和=的运算符重载,所以下面这几个直接复用前面的东西就行, 注意上面的写法用的是字符串函数进行比较,但是库里面用的是模板,所以这里有出入,如果用模板,就不能这样比较了

 4.3  bool operator<=(const String& s) const
  1. bool operator<=(const String& s) const
  2. {
  3. return *this < s || *this == s;
  4. }
4.4 bool operator>(const String& s) const
  1. bool operator>(const String& s) const
  2. {
  3. return !(*this <= s);
  4. }
4.5  bool operator>=(const String& s) const 
  1. bool operator>=(const String& s) const
  2. {
  3. return !(*this < s);
  4. }
 4.6  bool operator!=(const String& s) const
  1. bool operator!=(const String& s) const
  2. {
  3. return !(*this == s);
  4. }

 五  字符串操作 

5.1  截取操作

String substr(size_t pos = 0, size_t len = npos)const 

  1. String substr(size_t pos = 0, size_t len = npos)const
  2. {
  3. assert(pos >= 0 && pos < _size);
  4. size_t end = len + pos;//最后的位置
  5. String s = "";
  6. if (len == npos || pos + len > _size)//如果长度已经大于当前字符串长度
  7. {
  8. len = _size - pos;//新长度就等于pos到_size这么长
  9. end = _size;//
  10. }
  11. s.reserse(len);//开辟空间
  12. for (int i = pos; i < end; i++)//从pos开始到end结束
  13. {
  14. s += _str[i];
  15. }
  16. return s;
  17. }

 测试样例:

5.2  查找操作

size_t find(char c, size_t pos = 0)const

  1. size_t find(char c, size_t pos = 0)const
  2. {
  3. for (int i = pos;i < _size; i++)
  4. {
  5. if (_str[i] = c)
  6. {
  7. return i;
  8. }
  9. }
  10. return npos;
  11. }

查找一个字符 之间从pos位置开始遍历就行了

size_t find(const char* s, size_t pos = 0)const

  1. size_t find(const char* s, size_t pos = 0)const
  2. {
  3. char* p = strstr(_str + pos, s);
  4. if (p)
  5. {
  6. return p - _str;
  7. }
  8. else
  9. {
  10. return npos;
  11. }
  12. }

查找一个字符直接用库函数strstr就行 

测试用例: 

六  流插入流提取

由于这里的流插入和流提取不会涉及到私有的成员变量,所以不用写成友员函数

6.1  ostream& operator<<(ostream& out, const String& s)
  1. ostream& operator<<(ostream& out, const String& s)
  2. {
  3. for (auto ch : s)
  4. {
  5. out << ch;
  6. }
  7. return out;
  8. }
6.2   istream& operator>>(istream& in, String& s)
  1. //流提取
  2. istream& operator>> (istream& in, string& s)
  3. {
  4. s.clear();
  5. char ch = in.get();
  6. while (ch != ' ' && ch != '\n')
  7. {
  8. s += ch;
  9. ch = in.get();
  10. }
  11. return in;
  12. }

对于上面这段代码来说,我们首先要用一个clear去清理一下,因为不清理会导致之前的数据存在。

还有一点就是这段代码并不好,因为读字符的时候可能会导致频繁的扩容,我们电脑上面的程序可不止一个,不能一直中断其他程序,来进行这个,这样对于计算机的消耗有点大

  1. istream& operator>>(istream& in, String& s)
  2. {
  3. char buff[129];
  4. size_t i = 0;
  5. char ch;
  6. ch = in.get();
  7. while (ch != ' ' && ch != '\0')
  8. {
  9. buff[i++] = ch;
  10. if (i == 128)
  11. {
  12. buff[i] = '\0';
  13. s += buff;
  14. i = 0;
  15. }
  16. ch = in.get();
  17. }
  18. if (i > 0)
  19. {
  20. buff[i] = '\0';
  21. s += buff;
  22. }
  23. return in;
  24. }

这段代码就是对之前的一个改良,设置一个数组去存, 当存到128个字符的时候再一起把它放进字符串里面去,最后还有判断一下如果i!=128的情况即可

 七  string与string相加

String operator+(const String& s2)

这里用成员函数来写,库里面用的是非成员函数

  1. String operator+(const String& s2)
  2. {
  3. String ret;
  4. ret._size = _size + s2._size;
  5. ret._str = new char[_capacity + s2._capacity];
  6. strcpy(ret._str, _str);
  7. strcpy(ret._str + _size, s2._str);
  8. return ret;
  9. }

先开空间,然后把两个字符串放进去就行。

string类模拟实现完整代码

  1. #pragma once
  2. #include<iostream>
  3. #include<assert.h>
  4. using namespace std;
  5. class String
  6. {
  7. public:
  8. //迭代器
  9. typedef char* iterator;
  10. typedef char* const_iterator;
  11. iterator begin()
  12. {
  13. return _str;
  14. }
  15. iterator end()
  16. {
  17. return _str + _size;
  18. }
  19. const_iterator begin()const
  20. {
  21. return _str;
  22. }
  23. const_iterator end()const
  24. {
  25. return _str + _size;
  26. }
  27. //构造函数
  28. String(const char* str = "") :_size(strlen(str)), _capacity(_size)
  29. {
  30. _str = new char[_capacity+1];
  31. strcpy(_str, str);
  32. }
  33. //析构函数
  34. ~String()
  35. {
  36. delete[] _str;
  37. _str = nullptr;
  38. _size = 0;
  39. _capacity = 0;
  40. }
  41. //拷贝构造
  42. String(const String& s):_str(nullptr),_size(s._size), _capacity(s._capacity)
  43. {
  44. _str = new char[_capacity + 1];
  45. strcpy(_str, s._str);
  46. _size = s._size;
  47. _capacity = s._capacity;
  48. }
  49. //下表访问
  50. char& operator[](size_t pos)
  51. {
  52. assert(pos < _size||pos>=0);
  53. return _str[pos];
  54. }
  55. void swap(String& s)
  56. {
  57. std::swap(_str, s._str);
  58. std::swap(_size, s._size);
  59. std::swap(_capacity, s._capacity);
  60. }
  61. //赋值运算符重载
  62. String&operator=(String tmp)
  63. {
  64. swap(tmp);
  65. return *this;
  66. }
  67. //Capacity
  68. size_t size()const
  69. {
  70. return _size;
  71. }
  72. size_t capacity()const
  73. {
  74. return _capacity;
  75. }
  76. size_t max_size()const
  77. {
  78. return 4294967291;
  79. }
  80. bool empty()const
  81. {
  82. return _size == 0;
  83. }
  84. void reserse(size_t n)
  85. {
  86. if (n > _capacity)
  87. {
  88. char* tmp = new char[n + 1];
  89. strcpy(tmp, _str);
  90. delete[]_str;
  91. _str = tmp;
  92. }
  93. _capacity = n;
  94. }
  95. void resize(size_t n, char ch = '\0')
  96. {
  97. if (n < _size)
  98. {
  99. _str[n] = '\n';
  100. _size = n;
  101. }
  102. else
  103. {
  104. reserse(n);
  105. while (_size < n)
  106. {
  107. _str[_size] = ch;
  108. _size++;
  109. }
  110. _str[_size] = '\0';
  111. }
  112. }
  113. //Element access
  114. char& back()
  115. {
  116. return _str[_size - 1];
  117. }
  118. const char& back()const
  119. {
  120. return _str[_size - 1];
  121. }
  122. char& front()
  123. {
  124. return _str[0];
  125. }
  126. const char& front()const
  127. {
  128. return _str[0];
  129. }
  130. //Modifiers
  131. void append(const char* str)
  132. {
  133. size_t n = _size + strlen(str);
  134. if (n > _capacity)
  135. {
  136. reserse(n);
  137. _capacity = n;
  138. }
  139. strcat(_str, str);
  140. _size += strlen(str);
  141. }
  142. void push_back(char ch)
  143. {
  144. if (_size == _capacity)
  145. {
  146. reserse(_capacity == 0 ? 4 : 2 * _capacity);
  147. }
  148. _str[_size] = ch;
  149. _size++;
  150. _str[_size] = '\0';
  151. }
  152. String& operator+=(const String& s)
  153. {
  154. append(s._str);
  155. return *this;
  156. }
  157. String& operator+=(const char* str)
  158. {
  159. append(str);
  160. return *this;
  161. }
  162. String& operator+=(char ch)
  163. {
  164. push_back(ch);
  165. return *this;
  166. }
  167. void insert(size_t pos, char ch)
  168. {
  169. assert(pos <= _size && pos >= 0);
  170. if (_size == _capacity)
  171. {
  172. reserse(_capacity == 0 ? 4 : _capacity * 2);
  173. }
  174. size_t end = _size + 1;
  175. while (end > pos)
  176. {
  177. _str[end] = _str[end-1];
  178. end--;
  179. }
  180. _str[pos] = ch;
  181. _size++;
  182. }
  183. void insert(size_t pos, const char* str)
  184. {
  185. assert(pos <= _size && pos >= 0);
  186. int len = strlen(str);
  187. if (_size + len > _capacity)
  188. {
  189. reserse(_size + len);
  190. }
  191. size_t end = _size+1;
  192. while (end > pos)
  193. {
  194. _str[end + len] = _str[end-1];
  195. end--;
  196. }
  197. strncpy(_str + pos, str, len);
  198. _size += len;
  199. }
  200. void erase(size_t pos = 0, size_t len = npos)
  201. {
  202. assert(pos >= 0 && pos < _size);
  203. if (len == npos||pos+len>_size)
  204. {
  205. _str[pos] = '\0';
  206. _size = pos;
  207. }
  208. else
  209. {
  210. size_t end = pos + len;
  211. while (end <= _size)
  212. {
  213. _str[end - len] = _str[end];
  214. end++;
  215. }
  216. _size -= len;
  217. }
  218. }
  219. //String operations:
  220. const char* c_str()const
  221. {
  222. return _str;
  223. }
  224. const char* data()const
  225. {
  226. return _str;
  227. }
  228. size_t find(char c, size_t pos = 0)const
  229. {
  230. for (int i = pos;i < _size; i++)
  231. {
  232. if (_str[i] == c)
  233. {
  234. return i;
  235. }
  236. }
  237. return npos;
  238. }
  239. size_t find(const char* s, size_t pos = 0)const
  240. {
  241. char* p = strstr(_str + pos, s);
  242. if (p)
  243. {
  244. return p - _str;
  245. }
  246. else
  247. {
  248. return npos;
  249. }
  250. }
  251. String substr(size_t pos = 0, size_t len = npos)const
  252. {
  253. assert(pos >= 0 && pos < _size);
  254. size_t end = len + pos;
  255. String s = "";
  256. if (len == npos || pos + len > _size)
  257. {
  258. len = _size - pos;
  259. end = _size;
  260. }
  261. s.reserse(len);
  262. for (int i = pos; i < end; i++)
  263. {
  264. s += _str[i];
  265. }
  266. return s;
  267. }
  268. String operator+(const String& s2)
  269. {
  270. String ret;
  271. ret._size = _size + s2._size;
  272. ret._str = new char[_capacity + s2._capacity];
  273. strcpy(ret._str, _str);
  274. strcpy(ret._str + _size, s2._str);
  275. return ret;
  276. }
  277. bool operator<(const String& s) const
  278. {
  279. return strcmp(_str, s._str) < 0;
  280. }
  281. bool operator==(const String& s) const
  282. {
  283. return strcmp(_str, s._str) == 0;
  284. }
  285. bool operator<=(const String& s) const
  286. {
  287. return *this < s || *this == s;
  288. }
  289. bool operator>(const String& s) const
  290. {
  291. return !(*this <= s);
  292. }
  293. bool operator>=(const String& s) const
  294. {
  295. return !(*this < s);
  296. }
  297. bool operator!=(const String& s) const
  298. {
  299. return !(*this == s);
  300. }
  301. private:
  302. char* _str;
  303. size_t _size;
  304. size_t _capacity;
  305. static const size_t npos = -1;
  306. };
  307. //non_member constants
  308. ostream& operator<<(ostream& out, const String& s)
  309. {
  310. for (auto ch : s)
  311. {
  312. out << ch;
  313. }
  314. return out;
  315. }
  316. istream& operator>>(istream& in, String& s)
  317. {
  318. char buff[129];
  319. size_t i = 0;
  320. char ch;
  321. ch = in.get();
  322. while (ch != ' ' && ch != '\0')
  323. {
  324. buff[i++] = ch;
  325. if (i == 128)
  326. {
  327. buff[i] = '\0';
  328. s += buff;
  329. i = 0;
  330. }
  331. ch = in.get();
  332. }
  333. if (i > 0)
  334. {
  335. buff[i] = '\0';
  336. s += buff;
  337. }
  338. return in;
  339. }

总结

以上就是string的全部内容了,

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/714385
推荐阅读
相关标签