【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

相关内容

热门资讯

梦想的意义作文400字【精简... 梦想的意义作文400字 篇一梦想的意义每个人都有自己的梦想,无论大小,梦想对于一个人来说都有着深远的...
《三怪客泛舟记》英文读后感(... 《三怪客泛舟记》英文读后感 篇一After reading "The Adventures of t...
健身英语作文【最新6篇】 健身英语作文 篇一:健身的好处健身英语作文 篇二:如何制定健身计划健身英语作文 篇三   Sport...
初中英语作文(精选3篇) 初中英语作文 篇一My Favorite HobbyHobbies are an important...
英语作文Basketball... 英语作文Basketball 篇一Basketball is not just a sport, b...
娱乐活动的英语作文(经典6篇... 娱乐活动的英语作文 篇一Title: The Importance of Participating...
我的梦想英语作文【精彩6篇】 我的梦想英语作文 篇一My DreamEveryone has dreams. Dreams are...
英文寻物启事格式【精彩6篇】 Lost: Black Leather WalletLost on September 15th, ...
袁隆平英语作文(优选5篇) 袁隆平英语作文 篇一The Life and Achievements of Yuan Longpi...
介绍我自己英语作文 介绍我自己英语作文(精选24篇)  无论是身处学校还是步入社会,许多人都有过写作文的经历,对作文都不...
生活中的邮政英语作文【精选3... 生活中的邮政英语作文 篇一The Importance of Postal Services in ...
介绍朋友的英语作文【最新6篇... Introduction of My FriendEssay OneMy Friend LilyI ...
我的未来计划的英语作文【优秀... 我的未来计划的英语作文 篇一Title: My Future PlanAs a high schoo...
有关朋友的英语句子【优质3篇... 有关朋友的英语句子 篇一Friendship is one of the most precious...
各时态词语表示强调的英语例句... 各时态词语表示强调的英语例句 篇一In the English language, differen...
小学想象作文200字 小学想象作文200字  【篇一:未来世界】  我对未来世界总是充满幻想的。  假如在未采世界你想去天...
冬至的:冬至的介绍英语作文【... 冬至的:冬至的介绍英语作文 篇一Title: The Significance of Winter ...
作文 未来的电子书(经典3篇... 作文 未来的电子书 篇一随着科技的不断发展,电子书逐渐成为人们阅读的新选择。未来的电子书将会带来怎样...
写加拿大的英语作文100字(... 写加拿大的英语作文100字 篇一Canada: A Land of Diversity and Op...
学校英语作文 学校英语作文(7篇)  在学习、工作乃至生活中,大家或多或少都会接触过作文吧,作文是经过人的思想考虑...