1、为什么我们要学会写自定义string类

面试官爱考,你有办法吗,没有-.-

2、自定义string类应该如何正确书写

quote一句c++primer中的话:

类的安全性和处理正确性的不够,需要类的设计者(也就是我们)去写拷贝构造和赋值运算符重载函数,而最困难的不是如何书写而是让我们自己本身意识到需要这样做。


关于MyString不得不说的就是:深浅拷贝问题,这个究其原因就是它的成员变量是个char *类型的,如果我们懒到要让编译器自己帮我们去建构造、拷贝构造,赋值运算符重载这些函数,那么问题就是很大滴,因为它也很lazy,它做的操作就是让两个指针指向同一个地方。

举个栗子看:


那么下面就说说如何写一个正确的string:

首先c++中string它是个类对吧

那么我们就写一个类出来(成员函数和成员变量)

classMyString{private:char*_pData;//对,你没看错,只需要一个char型指针就可以实现哦public://首先一个类要有构造函数-->保证类的成员变量被正确的初始化//第一种写法----正确但不是最优MyString(char*pData=NULL){if(pData==NULL){_pData=newchar[1];_pData[0]='\0';}else{_pData=newchar[strlen(pData)+1];strcpy(_pData,pData);}}//第二种写法--比第一种更优:使用初始化列表MyString(char*pData=NULL):pData(newchar[strlen(pData)+1]){strcpy(_pData,pData);}//既然在构造中进行了new那么相对的是不是要在析构中去delete?~MyString(){if(_pData)//这里可以直接不用判断,thinkaboutwhy?{delete[]_pData;}}//拷贝构造-----?为什么需要写,因为成员变量是指针,如果我们不进行自己去写//就会出现安全性和正确性的问题,两个指针指向一个空间,当其中一个析构后,//另外一个就无法再去访问这片空间,会出现非法操作//考点:形参必须传入的是该类型的引用,不然在实参传给形参时//就会发生值传递,进行拷贝构造,那么这个拷贝构造就是一个死循环//第一种写法MyString(constMyString&mstr){if(strlen(mstr._pData)==0){_pData=newchar[1];_pData[0]='\0';}else{_pData=newchar[strlen(mstr._pData)+1];strcpy(_pData,mstr._pData);}}//第二种写法MyString(constMyString&mstr):_pData(newchar[strlen(mstr._pData)+1]){strcpy(_pData,mstr._pData);}//第三种写法:只有在构造和析构的时候开辟和释放空间,内存空间不易出错//不会出现MyString实例化对象的错误,考虑到了异常安全性MyString(constMyString&mstr):_pData(NULL)//_pData没有初始化,随机的空间,如果不赋值为空,会delete失败{MyStringtemp(mstr._pData);swap(temp._pData,_pData);}//赋值运算符重载//考点:1、返回值是该类型引用(考虑到有连等情况a=b=c)//考点:2、形参是const引用(不会改变形参并且效率高)//第一种写法--->缺点:如果在newchar[]出错的话,很有可能_pData就变成野指针//那么MyString返回的对象就是一个不正确的对象,有异常安全性问题MyString&operator=(constMyString&mstr){//考点:3、自己给自己赋值的情况,有没有考虑到!if(this!=&mstr){//考点:4、先释放,一定是释放[]_pData,原因就是构造的方式delete[]_pData;//再开辟_pData=newchar[strlen(mstr._pData)+1];strcpy(_pData,mstr._pData);}return*this;}//第二种写法MyString&operator=(constMyString&mstr){//先开辟char*temp=newchar[strlen(mstr._pData)+1];if(temp==NULL){return*this;}//在释放delete[]_pData;_pData=temp;strcpy(_pData,mstr._pData);return*this;}//第三种写法MyString&operator=(MyStringmstr){swap(mstr._pData,_pData);return*this;}//更优写法MyString&operator=(constMyString&mstr){if(&mstr!=this){MyStringtemp(mstr._pData);swap(temp._pData,_pData);}return*this;}//String对象转换成constchar*constchar*C_str()const{return_pData;}//求字符串长度size_tSize(){returnstrlen(_pData);}//判断是否相等booloperator==(constMyString&mstr)const{if(&mstr!=this){if(!strcmp(_pData,mstr._pData)){returnfalse;}}returntrue;}//某个字符charoperator[](size_tpos)const{if(pos<strlen(_pData)&&pos>=0){return_pData[pos];}else{return0;}}//字符串比较intoperator<(constMyString&mstr)const{inttruth=strcmp(_pData,mstr._pData);if(truth>0){return-1;}elseif(truth==0){return0;}else{return1;}}};