用char*管理String类的内存,new动态分配,在析构函数中delete char*指向的new出来的内存,一个string类需要实现那些接口可参考标准库里的string:  http://www.cplusplus.com/reference/string/string/

  • 实现思路是:在创建String、String需要伸缩(如赋值时需要调整大小、字符串相加也需要更大的空间)时重新new内存,并释放掉原有内存;标准库string的空间是预先分配的,有多余的空间可用,如果string需要伸缩,就开辟新的内存空间。
  • >>重载的思路是:用cin.getline来读取标准输入到字符指针指向的空间——空间有个预设的大小,如100,可以接收包含有空格的字符串
  • String初始化为空字符串("\0"或 ""是等价的),也需要new字符数组,这样才能delete,如果用char *data="\0",不能用delete释放不是new出来的内存
  • []需要重载两个版本,const版本 const char& operator[](size_t index) const; const成员函数的this指针隐式的转换为指向常量的指针: operator(const  String *this, size_t index),const对象只能调用const menber function
  • 不需要重载解引用*和取地址&,它们对自定义的类型也支持
  • +=调用了operator+,问为什么operator+要返回引用,而不能返回对象?
  • 没有实现重载的relational operators
  • 相比标准库,自定义的String实现的接口很少,似乎什么都做不了,只能创建,赋值,输出,访问元素,甚至连标准库里的string开发中也不好用:为什么大多数的C++的开源库都喜欢自己实现一个string
  • new管理内存是否存在memory leak,是否有隐含的错误?
  1. #include<iostream>
  2. #include<string>
  3. #include<vector>
  4. #include<algorithm>
  5. #include<cstdio>
  6. #include<complex>
  7. #include<new>
  8. #include<memory>
  9. #include<exception>
  10. using namespace std;
  11. // interfaces should supported
  12. //用char*管理内存
  13. class String
  14. {
  15. public:
  16. String();
  17. String(const char*s);
  18. String(size_t n, const char c);//用字符c填充String
  19. String(const String&s);
  20. String& operator=(const String&rhs);
  21. String& operator=(const char*c);
  22. char& operator[](size_t index);//要提供[]的两个版本
  23. const char& operator[](size_t index)const;
  24. String & operator*();//解引用重载是多余的,语言本身支持对所有类型的指针解引用,包括了自定义类型
  25. String& operator+(const String&rhs);
  26. String& operator+=(const String&rhs);
  27. bool operator==(const String&rhs);
  28. friend bool operator<(const String&lhs, const String&rhs);
  29. friend ostream& operator<<(ostream& os, const String&rhs);
  30. friend istream& operator>>(istream& in, String&rhs);
  31. size_t size(); //如果是size_t length()会导致。。。。。
  32. bool empty();
  33. const char* c_str();
  34. ~String();
  35. private:
  36. char * data;
  37. size_t length;
  38.  
  39. };
  40. String::String() //类外面定义menber function ,域作用符
  41. {
  42. this->data = new char[](); //空字符串 ,strlen对data运算得到的长度为0
  43. data[] = '\0';
  44. (*this).length = ;
  45. }
  46. String::String(const char*s) //允许implicit类型转换
  47. {
  48. // 不能用data=s;这导致创建的String对象与s共享了字符,而不是副本
  49. length = strlen(s);
  50. data = new char[length + ]();//value initialization,申请了字符指针指向的内存区域
  51. strcpy(data, s);
  52. *(data + length) = '\0';
  53. }
  54. String::String(size_t n, const char c)
  55. {
  56. length = n;
  57. data = new char[length + ]();
  58. for (size_t i = ; i < length;i++)
  59. {
  60. *(data + i) = c;
  61. }
  62. *(data + length) = '\0';
  63. }
  64. String::String(const String&s)
  65. {
  66. length = s.length;
  67. data = new char[length + ](); //untill deconstructor to destory newed memory
  68. for (size_t i = ; i < length;i++)
  69. {
  70. data[i] = s.data[i];
  71. }
  72. data[length] = '\0';
  73. }
  74. String& String::operator=(const String&rhs)
  75. {
  76. if (this->data == rhs.data) return *this;// 支持*this==rhs的关系比较操作吗?
  77.  
  78. //assign 不是初始化,不需要申请内存空间,拷贝构造需要 ,但是原String与rhs大小可能不一样
  79. delete[]data; //会导致重复删除data所指内存吗??
  80.  
  81. length = rhs.length;
  82. data = new char[length + ]();
  83. //如果发生异常
  84.  
  85. if (data == NULL) throw "allocate memory failed in copy ctr";
  86. for (size_t i = ; i < length; i++)
  87. {
  88. data[i] = rhs.data[i];
  89. }
  90. data[length] = '\0';
  91. }
  92. char& String::operator[](size_t index)
  93. {
  94. if (index >= length||index<) throw "out of range";
  95. return data[index];//如果data指向的字符串为"dhaj"这种不可修改的,会导致返回的引用不能有s[i]='c'的修改操作
  96. }
  97. String& String:: operator*()
  98. {
  99. if (this == NULL) throw "dereferrence null pointer ";
  100. return *this;
  101. }
  102. String& String::operator+(const String&rhs)//a+b形式,也不改变a
  103. {
  104. String s;//不可伸缩,不能用来存a+b的结果
  105. int len = strlen(this->data) + strlen(rhs.data);
  106. char *p = new char[len + ]();
  107. for (size_t i = ; i < strlen(this->data); i++)
  108. {
  109. p[i] = this->data[i];
  110. }
  111. for (int j = strlen(this->data),i=; j < len; j++,i++)
  112. {
  113. p[j] = rhs.data[i];
  114. }
  115. p[len] = '\0';
  116. String *t = new String(p); //new了一个p,一个t,可以释放掉p,因为t是p的副本
  117. delete[]p;
  118. return *t;//返回了堆上的引用,再c=a+b这种使用后,c是会析构的,但中间这个看不见的对象不会析构
  119. }
  120. String& String::operator+=(const String&rhs)
  121. {
  122. *this = *this + rhs;
  123. //释放掉原来的a,申请新空间
  124. return *this;
  125. }
  126. bool String::operator==(const String&rhs)//比较是否相等,而不是相同
  127. {
  128. if (this->length != rhs.length) return false;
  129. int i = ;
  130. for (; (*this).data[i] == rhs.data[i]; i++);
  131. if (i != (rhs.length + )) return false;
  132. else return true;
  133. }
  134. bool operator<(const String&lhs, const String&rhs)
  135. {
  136. return true;
  137. }
  138. ostream& operator<<(ostream& os, const String&rhs) //申明为友元函数。调用方式为cout<<s,申明为men fun,调用形式为s<<cout
  139. {
  140. os << rhs.data;//输出null pointer会未定义行为
  141. return os;
  142. }
  143. istream& operator>>(istream& is, String&rhs)
  144. {//输入一个字符串到字符指针,字符指针需要预先分配一定大小的空间,如何根据输入的字符串调整空间大小
  145. delete[]rhs.data;
  146. rhs.data = new char[]();
  147. is.getline(rhs.data, );//最后位置自动置为'\0',所以最多存49个字符,可接收空格
  148. rhs.length = strlen(rhs.data);
  149. return is;
  150. }
  151. size_t String::size()
  152. {
  153. return length;
  154. }
  155. bool String::empty()
  156. {
  157. if (length == ) return true;
  158. else return false;
  159. }
  160. const char* String::c_str()//返回指向对象局部部分的引用,指针,能用来修改原对象吗?
  161. {//如果为空串,也要返回data
  162. return data;
  163.  
  164. }
  165. String::~String()
  166. { // 析构会发生错误吗?
  167. //String创建时会new内存,当程序结束或局部String对象退出作用域时调用析构函数,释放该内存
  168. delete[]data; //如果String不是new出来的, 指针p指向它,delete p会导致错误,new出来的可以调用delete,这时会调用~String
  169. data = NULL;
  170. }
  171.  
  172. //int main()
  173. //{
  174. // String s;
  175. // cout << s << endl;
  176. // cout << strlen(s.c_str()) << endl;
  177. // String s1 = "whah";
  178. // cout << s1 << endl;
  179. // String s2 = s1;
  180. // cout <<"s2 length:"<< s2.size() << endl;
  181. // s = s2;
  182. // cout << "用s2赋值后的s: " << s << endl;
  183. // String s3(10, 'c');
  184. // cout << "字符填充初始化s3: " << s3 << " " << "s3 len= " << s3.size() << endl;
  185. // s3[0] = 'a';
  186. // cout << "下标修改s3后: " << s3 << endl;
  187. // String s4 = s2 + s3+"ad"; //支持连续的+
  188. // cout << s4 << endl;
  189. // String *sp = &s4;
  190. // cout << *sp << endl;
  191. // cout << strlen((*sp).c_str()) << endl;
  192. // String *q = new String(*sp);
  193. // cout << *q << endl;
  194. // delete q;
  195. //
  196. // char *sq = const_cast<char*> (s4.c_str());
  197. // sq[0] = 'l';
  198. // cout << sq << endl;
  199. // cout << s4 << endl;
  200. // const char *cptr = s2.c_str();
  201. // string s5 = "";
  202. // string s6 = "\0";
  203. // cout << s5 << "**" << s6 << s5.size() << s6.size() << endl;
  204. // string str = "jadj";
  205. // char *sptr = const_cast<char *> (str.c_str());
  206. // sptr[0] = 'd';
  207. // cout << sptr << " " << str << endl;
  208. // String s7(s2);
  209. // s7 += s4;
  210. // cout << "s7: " << s7.size() << s7 << endl;
  211. // const String s8("daj");
  212. // //s8[0]; 对const对象的[]调用,不能用non-const menber版本的operator[],要提供 const char& operator[]() const重载版本
  213. // //s8 = "djwajk0";
  214. //}
  215.  
  216. int main()
  217. {
  218. string s2;
  219. cin >> s2;
  220. cout << s2 << endl;
  221. String s, s1;
  222. cin >> s >> s1;//用Enter间隔字符串,可接含有空格的字符串
  223. cout << s <<"\n"<< s1 << endl;
  224. cout << s1.size() << endl;
  225. }

String类

自定义实现字符串string的接口的更多相关文章

  1. Java字符串String 集合的迭代器

    Java字符串String 我们知道Java的字符窜是Immutable(不可变)的,一旦创建就不能更改其内容了:平常我们对字符串的操作是最多的,其实对字符串的操作,返回的字符串都是新建的字符串对象, ...

  2. C# 字符串string类型转换成DateTime类型 或者 string转换成DateTime?(字符串转换成可空日期类型)

    在c#中,string类型转换成DateTime类型是经常用到的,作为基本的知识,这里在此做个小结.一般来说可以使用多种方法进行转换,最常用的就是使用Convert.ToDateTime(string ...

  3. 字符串string类型转换成DateTime或DateTime?类型

    常用的Convert.ToDateTime方法 //将含有正确日期格式的string类型转换成DateTime类型 string strDate = "2014-08-01"; D ...

  4. python 字符串 string

    字符串 string 语法: a = 'hello world!' b = "hello world!" 常用操作: 1.乘法操作是将字符串重复输出2遍 >>> ...

  5. C#如何生成JSON字符串提交给接口(服务器)

    C#如何生成JSON字符串提交给接口(服务器)   第一章:C#如何拿到从http上返回JSON数据? 第二章:C#如何解析JSON数据?(反序列化对象) 第三章:C#如何生成JSON字符串?(序列化 ...

  6. C#字符串string以及相关内置函数

    C#字符串string函数 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享. ...

  7. Spring关于使用注解@Configuration去配置FormattingConversionServiceFactoryBean来实现自定义格式字符串处理无效的问题(未找到是什么原因造成的)

    说明:在Spring MVC和Spring Boot中都能正常使用. 首先,我实现了一个自定义的注解,@Trimmed去除字符串String的前后空格. 如果是在Spring MVC的XML配置中,可 ...

  8. openresty开发系列18--lua的字符串string操作

    openresty开发系列18--lua的字符串string操作 string的相关操作 1)string.upper(s)接收一个字符串 s,返回一个把所有小写字母变成大写字母的字符串.print( ...

  9. ES6让字符串String增加了哪些好玩的特性呢?

    确实因为现在天气变热了,所以一天天的这么写我也很累.所以如果阅读的时候有什么错误还请大家指出来,不好意思.学习永无止境. OK,今天继续讲解ES6系列知识 学过上一节的解构赋值就知道,ES6确实给我们 ...

随机推荐

  1. linux下shell显示git当前分支

    function git-branch-name { git symbolic-ref HEAD 2>/dev/null | cut -d"/" -f 3 } functio ...

  2. java_第一年_JavaWeb(9)

    JavaBean是一个遵循某种特定写法的Java类,有以下特点: 必需具有一个无参的构造函数 属性必需私有化 私有化的属性必需通过public类型的方法暴露给其它程序,其方法命名也有一定的规范 范例: ...

  3. Educational Codeforces Round 69 (Rated for Div. 2) A~D Sloution

    A. DIY Wooden Ladder 题意:有一些不能切的木板,每个都有一个长度,要做一个梯子,求梯子的最大台阶数 做梯子的木板分为两种,两边的两条木板和中间的若干条台阶木板 台阶数为 $k$ 的 ...

  4. shell判断用户是否已经在系统中登录

  5. ViewMode

    一.ViewMode 实现使用场景-Model枚举的情景下, 注意:枚举声明在后台的时候,需要渲染界面,页面表格使用 Bootstrap Table插件-事先通过ajax 渲染(数据库读取值1.2.3 ...

  6. 毕设问题(1)表格table的表头自定义、复合表头,组合表格

    毕业设计,是一个web项目,遇到的些问题,记录下来.也许也有同样只知道一些,不是那么系统的学过的人,会遇到同样的问题,希望有所帮助. 百度知道有这样一个问题: bootstrap table 如何实现 ...

  7. EXCUTE JAVAScript点击事件

    # Execute Javascript document.getElementsByClassName('chooseFile')[${index}].arguments[0].click(); # ...

  8. js百度地图API创建弧线并修改弧线的弧度

    去百度API官网下载CurveLine.min.js,注意复制下来的Js前面的行号要删除. // 百度地图API功能 var map = new BMap.Map("container&qu ...

  9. fat文件系统

    在主引导区后面就是FAT表.从上面可以得知一个FAT表是229个扇区.它里边的内容很简单,里边的内容就是指出下一个簇在哪里.你的盘有多少个簇,那么它的FAT表就要有多少个项来描述它们.因为FAT16是 ...

  10. selenium与appium怎样联系

    appium是手机app端的自动化,它继承了webdriver(也就是selenium 2)          不过appium仍然需要通过selenium最后做测试工具,但是appium起到了一个连 ...