前言:
在前面我们已经学习了如何使用标准库中的string类,但作为一个合格的程序员,我们不仅要会用,还要知道如何实现string中的类函数等内容,今天我们就来讲解一下string的模拟实现
string的模拟实现中最重要的就是string类的构造、拷贝构造、赋值运算符重载以及析构函数
接下来我们就围绕这些重点进行学习
一、string类的构造
首先我们要清楚string类在底层实际上就是一个字符指针和许多类函数,所以它的类成员变量就是:
private: char* _str;
我们先把模拟构造给出来再来讲解:
//为了区分标准库,我们用String class String { public: String(const char* str = "") { if (str == nullptr) { assert(false); return; } _str = new char[strlen(str) + 1]; strcpy(_str, str); } void String_print() { cout << _str << endl; } private: char* _str; }; int main() { String s1("abc"); s1.String_print(); return 0; }
运行结果:
相信一定有细心的朋友已经注意到我们在给参数时并没有给任何东西,原因如下:
还有一点需要注意的是:我们在赋值时是创建一个新空间来储存,并不是直接赋值,这就涉及深拷贝的问题了,在下面我们讲拷贝构造的时候能更清晰的体现出来
二、string类的拷贝构造
模拟实现的代码如下:
String(const String& s) : _str(new char[strlen(s._str) + 1]) { strcpy(_str, s._str); }
在这里我们主要来讲解一下深拷贝和浅拷贝的问题,我们放在一个完整的代码实例:
class String { public: String(const char* str = "") { if (str == nullptr) { assert(false); return; } _str = new char[strlen(str) + 1]; strcpy(_str, str); } String(const String& s) : _str(new char[strlen(s._str) + 1]) { strcpy(_str, s._str); } void String_print() { cout << _str << endl; } private: char* _str; }; int main() { String s1("abc"); s1.String_print(); String s2(s1); s2.String_print(); return 0; }
运行结果:
错误示范:
三、string类的析构函数
由于string类对象不管以哪个方式创建时,都需要用new来开辟空间,所以string的析构函数写法为:
~String() { if (_str) //检查一下_str是否为空,如果为空就不用再释放空间了 { delete[] _str; _str = nullptr; } }
四、string类的运算符重载
string类的运算符重载整体来说没啥难度,在这里我们也不做过多讲解,重点来讲解一下operator=的两种写法
1、operator=的传统写法
String& operator=(const String& s) { if (s._str != _str) { char* ptr = new char[strlen(s._str) + 1]; //+1是因为要多开辟一个空间存放\0 strcpy(ptr, s._str); delete _str; //清空_str中可能有的数据 _str = ptr; } return *this; }
2、operator=的现代写法
String& operator=(String s) { swap(_str, s._str); //swap函数算法库中存在,所以可以直接使用 return *this; }
单从篇幅上来比较,现代写法要比传统写法精简的多,那么它们两个究竟是如何实现它们的功能的呢?我们看下面的分析:
· 传统写法:
传统写法函数的参数是后值的引用,我们通过创建一个新的字符指针,并开辟空间接受后值,再把这个新创建的指针的地址传给我们的对象,从而实现了operator=的功能
· 现代写法:
现代写法则聪明的使用了算法库中的swap函数,从而让函数达到一个很精简的效果,该函数的参数是后值的临时拷贝,本来就是深拷贝,所以通过swap交换即可
传统写法和现代写法的过程比较:
五、代码实例
//为了区分标准库,我们用String class String { public: String(const char* str = "") { if (str == nullptr) { assert(false); return; } _str = new char[strlen(str) + 1]; strcpy(_str, str); } String(const String& s) : _str(new char[strlen(s._str) + 1]) { strcpy(_str, s._str); } //现代写法 String& operator=(String s) { swap(_str, s._str); return *this; } 传统写法 //String& operator=(const String& s) //{ // if (s._str != _str) // { // char* ptr = new char[strlen(s._str) + 1]; //+1是因为要多开辟一个空间存放\0 // strcpy(ptr, s._str); // delete _str; //清空_str中可能有的数据 // _str = ptr; // } // return *this; //} void String_print() { cout << _str << endl; } ~String() { if (_str) //检查一下_str是否为空,如果为空就不用再释放空间了 { delete[] _str; _str = nullptr; } } private: char* _str; }; int main() { String s1("abc"); s1.String_print(); String s2(s1); s2.String_print(); String s3 = s2; s3.String_print(); return 0; }
运行结果:
六、总结
以上就是string模拟实现的比较重要的部分,其他类函数我们并没有写出来,但难度都不大,感兴趣的老铁可以自己摸索一下或者在网上搜一下它的实现
感谢各位大佬观看,创作不易,还请一键三连!!!