🎉个人名片:
🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🙈个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉
————————————————
🎉文章简介:
🎉本篇文章对 string的模拟实现 等相关知识 学习的相关知识进行分享!
💕如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加 油,一起奔跑,让我们顶峰相见!!!🎉🎉🎉
———————————————————————————
一.前言
上篇文章*《C++string类的介绍及常用函数用法总结》*(文章链接: link)相信大家已经对string类的使用等方面详细了解了,为了更好的了解string的特性,今天我们通过string类的底层结构来手撕一个属于我们自己的类,方便更加深刻的理解这部分内容。
二.string类的模拟实现
先看一下string类里面所需要包含的成员变量:
private:char* _str; //指向存储字符串的指针size_t _size; //记录存储的有效数据个数size_t _capacity; //记录空间大小
重点实现的函数
一.构造函数
string(const char* str = "") //空字符串里面默认放的\0{_size = strlen(str);_capacity = _size;_str = new char[_capacity+1];strcpy(_str, str);}
避坑
常见错误与不合适的写法写法:
第一种:
这种是直接将成员变量全部初始化为0处理;
string():_str(nullptr),_size(0) ,_capacity(0)
{
}
不合理之处:
1.库里面string类既能能用常量字符串去构造对象,也可以无参构造对象,这样写不能达到和库里面的一样;
2._str是指向一个字符串的指针,应该以 ‘\0’ 结束,直接初始化为nullptr不能达到该效果;
3.其他函数对指针处理不当,很有可能会对指针进行解引用访问,会对空指针解引用;
第二种:
1.库里面string类既能能用字符串去构造对象,也可以无参构造对象,这样写不能达到和库里面的一样;
2.这样写构造函数效率低,每次初始化变量时都要去计算str长度,虽然可以先初始化_size,再去用_size去初始化其他变量,但是必须保证成员变量先声明_size;初始化顺序与声明顺序一样才行,代码维护性低;
string(const char* str):_str(new char[strlen(str) + 1]),_size(strlen(str)) //不合适的写法,_capacity(strlen(str)){strcpy(_str, str); //会将\0拷贝进去}
第三种:
1.错误写法,将’\0’赋值给str,类型不匹配,会报错;
string(const char* str='\0') //会报错,类型不匹配{_str = new char[1];_size = 0; _capacity = 0;_str[0] = '\0';}
二.拷贝构造函数
第一种:传统写法
//s1(s2)
string(const string& s)
{_str = new char[s._capacity + 1]; //开空间strcpy(_str,s._str); //拷贝_size = s._size; //赋值_capacity = s._capacity;}
第二种:现代写法
直接用s的_str构造tmp对象,然后两个对象交换即可;
string(const string& s){string tmp(s._str);swap(tmp);}
三.赋值运算符重载
第一种:传统写法
//s1=s2string& operator=(const string& s){char* tmp = new char[s._capacity + 1]; //开空间strcpy(tmp, s._str); //拷贝std::swap(tmp, _str); //交换指针_size = s._size; //赋值_capacity = s._capacity;return *this;}
第二种.现代写法
//s1=s2string& operator=(string s){swap(s);return *this;}
这里的巧妙在于没有用传引用传参,用的传值传参,s是s2的拷贝,s的改变不影响s2,调用上面实现的swap函数,交换s与s1,s1就指向了s指向的空间,_size和_capacity都与s的一样,出了作用域,s会调用析构函数清理掉s1之前的空间;
四.析构函数
~string(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}
五.运算符[ ]重载
char operator[](size_t pos){return _str[pos]; //返回对应的值}char operator[](size_t pos)const{return _str[pos];}
六.流提取运算符重载
ostream& operator<<(ostream& out, const string& s)
{for (int i = 0; i < s.size(); i++){cout <<s[i];}cout << endl;return out;
}
七.流插入运算符重载
注意:
这里不能使用 scanf 和 getchar ,因为他们是遇到空格或则\0就会停止获取,就导致ch不会等于’ ’ 和 ‘\0’,那么while循环无法结束;这里使用的是istream类里面的get函数;
istream& operator>>(istream& in, string& s){char ch;ch = in.get(); while (ch!=' '&&ch!='\0'){s += ch; //尾插到sch = in.get(); }return in;}
八.迭代器的实现
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{return _str;
}
const_iterator begin()const
{return _str;
}
iterator end()
{return _str + _size;
}
const_iterator end()const
{return _str+_size;
}