自我实现一个简洁版的String类——1
在C++中有C没有的string字符串类型,string类型的数据其实是一个指向字符串首地址的指针变量,因此在string类的默认成员函数拷贝构造和赋值运算符的重载就会涉及到深浅拷贝的问题,一不小心要么就是内存泄露要么就是多次释放同一块空间导致程序崩溃,下面就来模拟实现一个简洁版的String类:
既然是指向一个字符串的指针,因此类的成员变量就需要有一个char*类型的指针;
#include<iostream>#include<string.h>usingnamespacestd;classCMyString{public:CMyString(constchar*str);CMyString(constCMyString&s);CMyString&operator=(CMyStrings);//CMyString&operator=(constCMyString&s);~CMyString();voidprint_string();private:char*_str;};
上面为简单的CMyString类的声明,接下来要实现最主要的四个默认的成员函数:
构造函数主要是为成员变量_str分配内存空间并且初始化为形参的值;
CMyString::CMyString(constchar*str)//含参的构造函数:_str(NULL){assert(str);_str=newchar[_capacity];strcpy(_str,str);}CMyString::CMyString()//默认的构造函数:_str(NULL){}
拷贝构造就会涉及到了深浅拷贝的问题,因为不能使两个字符串的指针指向同一块地址空间:
CMyString::CMyString(constCMyString&s):_str(NULL){CMyStringtmp(s._str);//用前面实现的构造函数构造出一个值为s._str的临时类对象swap(_str,tmp._str);//交换临时类的字符串和_str,这样当tmp出了作用域就会自动释放}
赋值运算符的重载函数同样会涉及到深浅拷贝的问题:
//这是一种比较现代的写法,没有用引用s就为一个临时的类对象,出了作用域就会自动调用析构函数CMyString&CMyString::operator=(CMyStrings){if(strcmp(s._str,_str)!=0)swap(_str,s._str);//交换二者的值就能将有效值赋给_str,而原来的值随s释放return*this;}//较为传统的写法,先要判断是否自己给自己赋值再释放自己空间,重新开辟一块空间拷贝所需值//CMyString&CMyString::operator=(constCMyString&s)//{//if(this!=&s)//{//delete[]_str;//_str=newchar[strlen(s.str)+1];//strcpy(_str,s._str);//}//return*this;//}
但是在上面注释掉的一种写法中存在一个问题,就是如果将自己本身的地址空间释放掉了之后,再去new一块空间有可能会new不出来,这样的话不仅不能成功赋值,连自身本就存在的值也丢掉了,因此可以优化为如下代码:
CMyString&CMyString::operator=(constCMyString&s){if(this!=&s){char*tmp=newchar[strlen(s.str)+1];if(tmp!=NULL){delete[]_str;_str=tmp;strcpy(_str,s.str);}}return*this;}
析构函数是在当类对象出了所在作用域时自动调用完成清理工作的:
CMyString::~CMyString(){if(_str!=NULL)//检查类成员是否为空,delete不能释放空指针{delete[]_str;_str=NULL;//防止出现野指针}}
最后一个print_string函数是为了打印验证结果,这里就不写了;
main函数:
intmain(){CMyStrings1("thisismystring...");s1.print_string();CMyStrings2("helloworld...");s2.print_string();CMyStrings3(s2);s3.print_string();s3=s1;s3.print_string();return0;}
运行程序结果如下:
《完》
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。