在C++中有C没有的string字符串类型,string类型的数据其实是一个指向字符串首地址的指针变量,因此在string类的默认成员函数拷贝构造和赋值运算符的重载就会涉及到深浅拷贝的问题,一不小心要么就是内存泄露要么就是多次释放同一块空间导致程序崩溃,下面就来模拟实现一个简洁版的String类:
既然是指向一个字符串的指针,因此类的成员变量就需要有一个char*类型的指针;
#include <iostream> #include <string.h> using namespace std; class CMyString { public: CMyString(const char* str); CMyString(const CMyString& s); CMyString& operator=(CMyString s); //CMyString& operator=(const CMyString& s); ~CMyString(); void print_string(); private: char* _str; };
上面为简单的CMyString类的声明,接下来要实现最主要的四个默认的成员函数:
构造函数主要是为成员变量_str分配内存空间并且初始化为形参的值;
CMyString::CMyString(const char* str) //含参的构造函数 :_str(NULL) { assert(str); _str = new char[_capacity]; strcpy(_str, str); } CMyString::CMyString() //默认的构造函数 :_str(NULL) {}
拷贝构造就会涉及到了深浅拷贝的问题,因为不能使两个字符串的指针指向同一块地址空间:
CMyString::CMyString(const CMyString& s) :_str(NULL) { CMyString tmp(s._str);//用前面实现的构造函数构造出一个值为s._str的临时类对象 swap(_str, tmp._str);//交换临时类的字符串和_str,这样当tmp出了作用域就会自动释放 }
赋值运算符的重载函数同样会涉及到深浅拷贝的问题:
//这是一种比较现代的写法,没有用引用s就为一个临时的类对象,出了作用域就会自动调用析构函数 CMyString& CMyString::operator=(CMyString s) { if(strcmp(s._str, _str) != 0) swap(_str, s._str);//交换二者的值就能将有效值赋给_str,而原来的值随s释放 return *this; } //较为传统的写法,先要判断是否自己给自己赋值再释放自己空间,重新开辟一块空间拷贝所需值 //CMyString& CMyString::operator=(const CMyString& s) //{ // if(this != &s) // { // delete[] _str; // _str = new char[strlen(s.str)+1]; // strcpy(_str, s._str); // } // return *this; //}
但是在上面注释掉的一种写法中存在一个问题,就是如果将自己本身的地址空间释放掉了之后,再去new一块空间有可能会new不出来,这样的话不仅不能成功赋值,连自身本就存在的值也丢掉了,因此可以优化为如下代码:
CMyString& CMyString::operator=(const CMyString& s) { if(this != &s) { char *tmp = new char[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函数:
int main() { CMyString s1("this is my string..."); s1.print_string(); CMyString s2("hello world..."); s2.print_string(); CMyString s3(s2); s3.print_string(); s3 = s1; s3.print_string(); return 0; }
运行程序结果如下:
《完》
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。