重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
1、为什么我们要学会写自定义string类
未央网站建设公司创新互联,未央网站设计制作,有大型网站制作公司丰富经验。已为未央数千家提供企业网站建设服务。企业网站搭建\成都外贸网站制作要多少钱,请找那个售后服务好的未央做网站的公司定做!
面试官爱考,你有办法吗,没有-.-
2、自定义string类应该如何正确书写
quote一句c++primer中的话:
类的安全性和处理正确性的不够,需要类的设计者(也就是我们)去写拷贝构造和赋值运算符重载函数,而最困难的不是如何书写而是让我们自己本身意识到需要这样做。
关于MyString不得不说的就是:深浅拷贝问题,这个究其原因就是它的成员变量是个char *类型的,如果我们懒到要让编译器自己帮我们去建构造、拷贝构造,赋值运算符重载这些函数,那么问题就是很大滴,因为它也很lazy,它做的操作就是让两个指针指向同一个地方。
举个栗子看:
那么下面就说说如何写一个正确的string:
首先c++中string它是个类对吧
那么我们就写一个类出来(成员函数和成员变量)
class MyString { private: char *_pData;//对,你没看错,只需要一个char型指针就可以实现哦 public: //首先一个类要有构造函数-->保证类的成员变量被正确的初始化 //第一种写法----正确但不是最优 MyString(char *pData=NULL) { if (pData==NULL) { _pData=new char[1]; _pData[0]='\0'; } else { _pData=new char[strlen(pData)+1]; strcpy(_pData,pData); } } //第二种写法--比第一种更优:使用初始化列表 MyString(char *pData=NULL) :pData(new char[strlen(pData)+1]) { strcpy(_pData,pData); } //既然在构造中进行了new那么相对的是不是要在析构中去delete? ~MyString() { if (_pData)//这里可以直接不用判断,think about why? { delete []_pData; } } //拷贝构造-----?为什么需要写,因为成员变量是指针,如果我们不进行自己去写 //就会出现安全性和正确性的问题,两个指针指向一个空间,当其中一个析构后, //另外一个就无法再去访问这片空间,会出现非法操作 //考点:形参必须传入的是该类型的引用,不然在实参传给形参时 //就会发生值传递,进行拷贝构造,那么这个拷贝构造就是一个死循环 //第一种写法 MyString(const MyString &mstr) { if (strlen(mstr._pData)==0) { _pData=new char[1]; _pData[0]='\0'; } else { _pData=new char[strlen(mstr._pData)+1]; strcpy(_pData,mstr._pData); } } //第二种写法 MyString(const MyString &mstr) :_pData(new char[strlen(mstr._pData)+1]) { strcpy(_pData,mstr._pData); } //第三种写法:只有在构造和析构的时候开辟和释放空间,内存空间不易出错 //不会出现MyString实例化对象的错误,考虑到了异常安全性 MyString(const MyString &mstr) :_pData(NULL) //_pData没有初始化,随机的空间,如果不赋值为空,会delete失败 { MyString temp(mstr._pData); swap(temp._pData,_pData); } //赋值运算符重载 //考点:1、返回值是该类型引用(考虑到有连等情况a=b=c) //考点:2、形参是const 引用(不会改变形参并且效率高) //第一种写法--->缺点:如果在new char[]出错的话,很有可能_pData就变成野指针 //那么MyString返回的对象就是一个不正确的对象,有异常安全性问题 MyString& operator=(const MyString &mstr) { //考点:3、自己给自己赋值的情况,有没有考虑到! if (this!=&mstr) { //考点:4、先释放,一定是释放[]_pData,原因就是构造的方式 delete []_pData; //再开辟 _pData=new char[strlen(mstr._pData)+1]; strcpy(_pData,mstr._pData); } return *this; } //第二种写法 MyString &operator=(const MyString &mstr) { //先开辟 char *temp=new char[strlen(mstr._pData)+1]; if (temp==NULL) { return *this; } //在释放 delete []_pData; _pData=temp; strcpy(_pData,mstr._pData); return *this; } //第三种写法 MyString &operator=(MyString mstr) { swap(mstr._pData,_pData); return *this; } //更优写法 MyString &operator=(const MyString &mstr) { if(&mstr!=this) { MyString temp(mstr._pData); swap(temp._pData,_pData); } return *this; } //String对象转换成const char* const char* C_str()const { return _pData; } //求字符串长度 size_t Size() { return strlen(_pData); } //判断是否相等 bool operator==(const MyString &mstr)const { if (&mstr!=this) { if(!strcmp(_pData,mstr._pData)) { return false; } } return true; } //某个字符 char operator[](size_t pos)const { if (pos=0) { return _pData[pos]; } else { return 0; } } //字符串比较 int operator<(const MyString &mstr)const { int truth=strcmp(_pData,mstr._pData); if (truth>0) { return -1; } else if (truth==0) { return 0; } else { return 1; } } };