【string类的简单模拟实现】
创始人
2024-05-22 11:34:53
0

目录

1 类中成员变量的声明

2 迭代器

3 一些常用接口

4 六大默认函数

4.1 构造

4.2 拷贝构造

4.3 赋值运算符重载

4.4 析构

5 开空间&&增删查改

6 其他运算符重载


1 类中成员变量的声明

通过上一篇文章对string类的简单使用相信大家对于string类中成员变量已经很熟悉了,这里就不再多说了:

class string{private:char* _str;int _size;//当前有效数据个数int _capacity;//存储有效数据的最大容量,不包括'\0'static const size_t npos;typedef char* iterator;typedef const char* const_iterator;};

但是为了测试时避免与库里面的冲突我们就把该类放在一个独立的命名空间中:

namespace grm
{class string{private:char* _str;int _size;//当前有效数据个数int _capacity;//存储有效数据的最大容量,不包括'\0'static const size_t npos;typedef char* iterator;typedef const char* const_iterator;};
}

2 迭代器

        iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin()const{return _str;}const_iterator end()const{return _str + _size;}

3 一些常用接口

        size_t size()const     //无论是不是const对象都能够调用{return _size;}char* c_str()const{return _str;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos)const{assert(pos < _size);return _str[pos];}void clear()const{_str[0] = '\0';_size = 0;}size_t capacity()const{return _capacity;}bool empty()const{return _size == 0;}

4 六大默认函数

4.1 构造

       string(const char* s):_size(strlen(s)),_capacity(_size){_str = new char[_capacity + 1];//多开出一个空间用来存储'\0'strcpy(_str, s);}

但是我们发现如果是无参又该怎么办?

有人会说像这样特殊处理一下就好了:

        string():_str(new char[1]),_size(0),_capacity(0){_str[0] = '\0';}

这样处理是没有问题的,但是我们学过缺省参数,在这里能不能够给一个缺省值呢?缺省值又该给那个呢?

C++中是这样处理的:

        string(const char* s="")//给一个空字符串:_size(strlen(s)),_capacity(_size){_str = new char[_capacity + 1];//多开出一个空间用来存储'\0'strcpy(_str, s);}

缺省值给的是一个空字符串。

4.2 拷贝构造

传统写法:

        //传统写法string(const string& s):_size(s._size),_capacity(s._capacity){_str = new char[_capacity+1];strcpy(_str, s._str);}

这种写法就是自己手动开空间拷贝。

现代写法:我们发现上面我们已经实现好了默认的构造函数,我们可以直接用构造函数来解决

        void swap(string& s){std::swap(s._str, _str);std::swap(s._capacity, _capacity);std::swap(s._size, _size);}//现代写法string(const string& s):_str(nullptr)//必须要给初始值,否则交换后调用析构函数就会析构随机值会崩溃,_size(0),_capacity(0){string tmp(s._str);swap(tmp);}

其中需要注意的是使用这种方式用初始化列表将_str初始化成nullptr,不然交换后调用tmp的析构函数就会释放随机地址而出错。

4.3 赋值运算符重载

与拷贝构造一样,赋值运算符重载也分为传统版本和现代版本。

传统版本:

        //传统写法string& operator=(const string& s){if (this != &s){//这种方式如果new失败了抛异常就会有问题,我们并不想_str维护的空间被释放delete[] _str;_str = new char[s._capacity+1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}

大家可以从注释中看见传统写法都是要自己手动开空间拷贝,而且大家也发现了代码中还多了一个判断this是否与&s相等,否则当直接delete_str后由于s与_str指向的是同一块空间,再对s解引用就是典型的野指针问题了。而且还有一个问题就是当我们new空间失败时我们并不想_str被释放,所以可以用下面这种写法:

        //传统写法string& operator=(const string& s){if (this != &s){char* tmp = new char[s._capacity+1];strcpy(tmp, s._str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}

而且大家发现没有这样写即使不用写上面的if判断程序依旧可以正常运行,但是加上判断当自己给自己赋值时可以减少拷贝。

现代写法 方法1:

        //现代写法 方法1:string& operator=(const string& s){if (this != &s) //这里加上判断条件在自己给自己赋值能够减少拷贝,不加也是没有问题的{string tmp(s);swap(tmp);}return *this;}

现代写法 方法2:

        //现代写法 方法2:string& operator=(string s){swap(s);return *this;}

这种方式就更加巧妙了,直接用了传值传参,而传值传参就是一个拷贝构造。

4.4 析构

        ~string(){if (_str){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}}

5 开空间&&增删查改

void reserve(size_t n) //这里要求开n个有效空间,不包括'\0'{if (_capacity < n){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void resize(size_t n, char ch = '\0'){if (n > _size){if (n > _capacity){reserve(n);}memset(_str + _size, ch, n - _size);}_size = n;_str[_size] = '\0';}
        void push_back(char ch){if (_capacity == _size)reserve(_capacity == 0 ? 4 : _capacity * 2);_str[_size] = ch;++_size;_str[_size] = '\0';}void append(const char* s){int len = strlen(s);if (_size + len > _capacity)reserve(_size + len);strcpy(_str + _size, s);_size += len;}string& operator+=(char ch){push_back(ch);return *this;}string& operator+= (const char* s){append(s);return *this;}size_t find(char ch){for (size_t i = 0; i < _size; i++)if (_str[i] == ch)return i;return -1;}size_t find(const char* s, size_t pos=0){int i = pos, j = 0;//i是主串遍历,j是子串遍历while (i < _size && j < strlen(s)){if (s[j] == _str[i]){i++;j++;}else{i = i - j + 1;j = 0;}}if (j == strlen(s))return i - j;elsereturn -1;}
        string& insert(size_t pos, const char* s)//在pos位置插入,字符串从pos位置开始插{assert(pos <= _size);int len = strlen(s);if (_size + len > _capacity)reserve(_size + len);int end = _size + len - 1;int gap = _size - pos + 1;while (gap--){_str[end] = _str[end - len];end--;}strncpy(_str + pos, s, len);_str[_size + len] = '\0';return *this;}string& erase(size_t pos, size_t len = npos){assert(pos < _size);if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos+1;}strcpy(_str + pos, _str + len + pos);_size -= len;return *this;}

这些代码我们之前上顺序表都已经比较详细的介绍了,大家可以参考参考。

我们可以自己测试一下来看看:

 

 可以发现是没有多大问题的。


6 其他运算符重载

        bool operator<(const string& s)const{return strcmp(_str, s._str)<0;}bool operator>(const string& s)const{return strcmp(_str, s._str) > 0;}bool operator<=(const string& s)const{return strcmp(_str, s._str) <= 0;}bool operator>=(const string& s)const{return strcmp(_str, s._str) >= 0;}bool operator!=(const string& s)const{return strcmp(_str, s._str) != 0;}ostream& operator<<(ostream& out, const string& s){//out << s.c_str();//能这么写吗? 不能,也许我们会在字符中间插入一个'\0'for (auto& e : s){out << e;}/*for (int i = 0; i < s.size(); i++){out << s[i];}*/return out;}istream& operator>>(istream& in, string& s){s.clear();//要加上这个,否则可能出错char ch = in.get();while (ch != '\0' && ch != '\n'){s += ch;ch = in.get();}return in;}

上面这几个比较可以自己重载成成员方法,当然也可以重载成全局函数。下面流提取运算符和流插入运算符我们在之前已经讲过了,里面需要注意的细节代码中都有注释。


有需要源码的老铁可以去博主的码云中获得:

nijhttps://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72https://gitee.com/monday-sky/text_cpp/commit/e4716c73bba49dd2bad8c86986d0cfe26beece72

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...