河南省建设厅网站中级职称,上海到北京高铁多少钱,外卖做的比较好的网站,中文电子商务网站模板文章目录前言一、包含的相关头文件二、构造和析构1.构造函数2.拷贝构造1.传统写法2.现代写法3.赋值运算符重载1.传统写法2.现代写法4.析构函数三、iterator四、modify1.push_back(尾插一个字符#xff09;2.append#xff08;尾插一个字符串#xff09;3.运算符重载1.尾插字…
文章目录前言一、包含的相关头文件二、构造和析构1.构造函数2.拷贝构造1.传统写法2.现代写法3.赋值运算符重载1.传统写法2.现代写法4.析构函数三、iterator四、modify1.push_back(尾插一个字符2.append尾插一个字符串3.运算符重载1.尾插字符2.尾插字符串4.clear5.insert1.插入一个字符2.插入一个字符串6.erase五、capacity1.size2.capacity3.empty4.resize5.reserve六、access1.普通对象的接口可读可写2.const对象的接口只读七、relational operators1.运算符重载2.运算符重载3.运算符重载4.运算符重载5.运算符重载6.运算符!重载八、String operations1.find1.找字符2.找子串2.c_str九、Non-member function overloads1.流插入2.流提取十、私有属性总结前言
因为学习了string的相关知识了解了string大部分接口的底层实现原理所以我决定自己模拟实现一个mini版的string类用来加深对string各方面知识的理解。 如果有错误或不足之处还望各位读者小伙伴们指出。 一、包含的相关头文件
#includeiostream
#includeassert.h
#includecstring
using std::ostream;
using std::istream;
using std:: cout;
using std:: endl;二、构造和析构
1.构造函数 //构造string(const char* str ){size_t len strlen(str);_capacity _size len;_str new char[_capacity 1];strcpy(_str, str);}2.拷贝构造
1.传统写法
该对象自己一点一点的进行深拷贝 //拷贝构造string(const string s){_str new char[s._capacity 1];_size s._size;_capacity s._capacity;strcpy(_str, s._str);}2.现代写法
找一个中间对象让这个中间对象用参数的值进行直接构造再将这个中间对象的内容与自己的内容进行交换。相较于传统写法现代写法更加简洁。 //拷贝构造string(const string s):_str(nullptr),//此处要注意将该对象的地址赋值为nullptr否则析构中间对象时会因为发生野指针的访问而导致程序崩溃。_size(0),_capacity(0){string temp(s);swap(temp);}此处的swap用的是string自己实现的swap为什么不用库里的swap呢因为库里的swap是进行深拷贝会降低效率。我们自己实现的swap只需要进行浅拷贝即将它们对应的资源进行交换即可。 void swap(string s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}3.赋值运算符重载
1.传统写法 //赋值运算符重载string operator(const string s){if (this ! s){char* temp new char[s._capacity 1];//用一个中间值记录新开辟的空间如果开辟空间成功再将该空间的地址给_str。避免因为开辟空间失败_str原本的内容也销毁的情况发生。strcpy(temp, s._str);delete[] _str;_str temp;_capacity s._capacity;_size s._size;}return *this;}2.现代写法
与拷贝构造的现代写法思想类似可以使程序更加简洁。并且此处不需要专门定义一个中间对象因为传值传参传过来的形参是实参拷贝构造出来的对象它就是一个很好的中间对象我们直接和它进行交换即可。 //赋值运算符重载string operator(string s){swap(s);return *this;}4.析构函数 //析构~string(){delete[] _str;_str nullptr;//释放指针所指向的空间后要将该指针置为空避免出现野指针的非法访问_size _capacity 0;}三、iterator
迭代器是一个使用起来像指针的东西实际上string的迭代器就是char*类型的指针因此我们先在最开始进行typedef
typedef char* iterator;定义两个迭代器分别指向字符串开头和结尾 iterator begin(){return _str;}iterator end(){return _str _size;}四、modify
1.push_back(尾插一个字符
string只提供了push_back的接口没有提供头插的接口因为头插需要移动数据效率很低所以尽量不要在string中使用头插。 void push_back(char c){if (_size _capacity){size_t newcapacity _capacity 0 ? 4 : _capacity * 2;//要考虑到如果初始字符串的容量为0的情况reserve(newcapacity);_capacity newcapacity;}_str[_size] c;_str[_size] \0;}2.append尾插一个字符串 void append(const char* str){size_t len strlen(str);if (len _size _capacity){reserve(len _size);}strcpy(end(), str);_size len;}3.运算符重载
1.尾插字符
尾插一个字符复用尾插 string operator(char c){push_back(c);return *this;}2.尾插字符串
尾插一个字符串复用append string operator(const char* str){append(str);return *this;}4.clear
清除string中所有元素 void clear(){_size 0;_str[0] \0;}5.insert
1.插入一个字符
在字符串某位置插入一个字符 // 在pos位置上插入字符c/字符串strstring insert(size_t pos, char c){assert(pos _size);if (_size 1 _capacity){reserve(_size 1);}for (size_t i _size 1; i pos; --i)//要注意避免i减为-1变成一个极大的无符号数导致死循环{_str[i] _str[i - 1];}_str[pos] c;_size;return *this;}2.插入一个字符串
在字符串某位置插入一个字符串 string insert(size_t pos, const char* str){assert(pos _size);size_t i 0;size_t len strlen(str);if (_size len _capacity){reserve(_size len);}for (i _size len; i pos len - 1; --i){_str[i] _str[i - len];}strncpy(_str pos, str, len);_size len;return *this;}6.erase
删除从字符串某位置开始某长度的子串如果不说明删除子串的长度则默认从开始位置到最后的所有内容都删除 // 删除pos位置上的元素string erase(size_t pos, size_t len npos){if (len npos || pos len _size){_str[pos] \0;_size pos;}else{strcpy(_str pos, _str pos len);_size - len;}return *this;}五、capacity
1.size
类外成员不能直接访问类的私有属性/数据因此需要提供一个接口进行访问数据但是要对数据进行保护因此用了const传参和传值返回。 访问string中的元素个数。 size_t size()const{return _size;}2.capacity
访问string的容量。 size_t capacity()const{return _capacity;}3.empty
判断字符串是否为空。 bool empty()const{if (_size 0){return true;}return false;}4.resize
修改字符串的元素个数可以尾插指定的字符未指定则默认插入’\0’。 void resize(size_t n, char c \0)//更改元素个数{if (n _size){_size n;_str[_size] \0;}else{reserve(n);//先扩容再加元素for (size_t i _size; i n; i){_str[i] c;}_str[n] \0;_size n;}}5.reserve
修改字符串的容量。 void reserve(size_t n)//更改容量大小{if (n _capacity){char* temp new char[n 1];//先开空间再拷贝值避免因为空间开辟失败的异常使_str原地址也丢失了strcpy(temp, _str);delete[] _str;_str temp;_capacity n;}}六、access
访问字符串中的字符运算符[]重载。
1.普通对象的接口可读可写 char operator[](size_t index)//普通对象的接口可读可写{assert(index _size);return _str[index];}2.const对象的接口只读 const char operator[](size_t index)const//const对象的接口只读{assert(index _size);return _str[index];}七、relational operators
1.运算符重载 bool operator(const string s){size_t len _size s._size ? _size : s._size;for (size_t i 0; i len; i){if ((*this)[i] s[i]){return false;}return true;}}2.运算符重载 bool operator(const string s){size_t len _size s._size ? _size : s._size;for (size_t i 0; i len; i){if ((*this)[i] s[i]){return false;}return true;}}3.运算符重载
复用。 bool operator(const string s){return !(*this s);}4.运算符重载
复用。 bool operator(const string s){return !(*this s);}5.运算符重载
复用和。 bool operator(const string s){return (!((*this) s)) (!((*this) s));}6.运算符!重载
复用。 bool operator!(const string s){return !((*this) s);}八、String operations
1.find
1.找字符
找一个字符第一次在字符串中出现的下标 // 返回c在string中第一次出现的位置(下标)size_t find(char c, size_t pos 0) const{assert(pos _size);for (size_t i 0; i _size; i){if ((*this)[i] c){return i;}}return npos;}2.找子串
找一个子串第一次出现在字符串中的下标 复用C语言对字符串的操作——strstr函数在一个字符串中找子串 // 返回子串s在string中第一次出现的位置(下标)size_t find(const char* s, size_t pos 0) const{assert(pos _size);const char* ptr strstr(_str pos, s);if (ptr nullptr){return npos;}else{return ptr - _str;}}也可以一个字符一个字符的遍历寻找 // 返回子串s在string中第一次出现的位置(下标)size_t find(const char* s, size_t pos 0) const{assert(pos _size);size_t i 0;while (i _size){int flag 0;if ((*this)[i] s[0]){size_t k i;for (size_t j 0; j strlen(s); j, k){if ((*this)[k] ! s[j]){flag 1;}}if (flag 0) return i;}i;}return npos;}2.c_str
返回字符串的地址 const char* c_str()const{return _str;}九、Non-member function overloads
1.流插入 ostream operator(ostream _cout, const string s){for (size_t i 0; i s.size(); i){_cout s[i];}return _cout;}2.流提取 istream operator(istream _cin, string s){s.clear();//将原来s中的值清除char buff[128] { \0 };size_t i 0;char ch _cin.get();//这里不能使用getc或者scanf函数的原因是他们都是按照空格 或者换行\n进行分割内容的所以无法取到空格和换行因此只能用get()while (ch ! || ch ! \n){if (i 127)//缓存部分满了{s buff;//将内容存入s同时将缓存部分情况i 0;}buff[i] ch;ch _cin.get();}return _cin;}十、私有属性 private:char* _str;size_t _capacity;size_t _size;const static size_t npos -1;//只有这个特例可以这样定义其他static数据成员都要在类内声明在类外定义。总结
以上就是今天要讲的内容本文介绍了作者自己实现的string类的相关类成员函数如果文章中的内容有错误或者不严谨的部分欢迎大家在评论区指出也欢迎大家在评论区提问、交流。 最后如果本篇文章对你有所启发的话希望可以多多支持作者谢谢大家