当前位置: 首页 > news >正文

php大流量网站开发规范做网站的尺寸1920

php大流量网站开发规范,做网站的尺寸1920,上海公司拍沪牌需要什么条件,天元建设集团有限公司商票string模拟实现 引言#xff08;实现概述#xff09;string类方法实现默认成员函数构造函数拷贝构造赋值运算符重载析构函数 迭代器beginend 容量size、capacity、emptyreserveresize 访问元素operator[] 修改insert插入字符插入字符串 appendpush_backoperatoreraseclearswa… string模拟实现 引言实现概述string类方法实现默认成员函数构造函数拷贝构造赋值运算符重载析构函数 迭代器beginend 容量size、capacity、emptyreserveresize 访问元素operator[] 修改insert插入字符插入字符串 appendpush_backoperatoreraseclearswap 比较运算符重载operatoroperator其他 查找查找字符查找字符串 非成员函数operatoroperator 源码概览总结 引言实现概述 在上一篇文章中我们介绍了string类的使用 戳我康string类的使用详解哦 在本篇文章中就要来模拟实现一下string类以帮助我们更好的理解与使用string 在我们模拟实现的string中要具备库中string所具有的主要接口例如默认成员函数、迭代器、容量、元素访问、运算符重载、非成员函数。其中只实现这些函数的常用重载形式。 我们将模拟实现的string类放在我们创建的命名空间内以防止与库中的string发生命名冲突。在以后的STL模拟实现时也会将其放在命名空间内。 string类的实现与之前C语言部分的顺序表类似结合类和对象的知识这个string类的属性有指向堆中一块用于存放字符序列的空间的指针_str、字符序列的字符个数_size、字符序列的容量_capacity。 string类方法实现 默认成员函数 构造函数 在构造函数部分就只实现用常量字符串构造string对象 在这个构造函数中参数类型就是const char*给这个参数一个空串作为缺省值 在函数内部首先assert判断参数是否为空指针 然后令_size的值等于常量字符串str的长度令_capacity等于_size的值 然后new一块空间将这块空间的指针赋给_str这里需要注意的是strlen计算字符串长度时是以\0为结束标志的所以在动态开辟空间时需要开辟_capacity 1个char的空间 最后使用memcpy将常量字符串中的数据拷贝到刚刚申请的空间中这里拷贝时也需要将\0拷贝进去所以要拷贝_size 1 个字节 string(const char* str ){assert(str);_size strlen(str);_capacity _size;_str new char[_capacity 1];memcpy(_str, str, _size 1);}拷贝构造 拷贝构造是构造函数的重载参数类型为const string如果不是引用就会导致无穷递归调用 实现拷贝构造时不能直接将原对象的_str直接赋值给新对象的_str否则就会导致浅拷贝这样在析构时同一块空间就要被析构两遍显然就会导致崩溃。所以我们需要新申请一块空间后将原对象的字符序列拷贝到新的空间。 先将原对象的_size 与 _capacity 直接赋值给新对象 然后new一块空间将这块空间的指针赋给_str这里需要注意的是在我们实现的string类中_capacity是不包括\0的所以在动态开辟空间时需要开辟_capacity 1个char的空间 最后使用memcpy将原对象中的字符序列拷贝到刚刚新开辟的空间中。 这里需要注意的是C字符串的结束标志为\0但string对象没有结束标志它的数据个数就是_size的值所以当这个字符序列的中间出现\0时使用strcpy就不会拷贝\0后面的数据所以这里使用包括后面都使用memcpy。 string(const string s){_size s._size;_capacity s._capacity;_str new char[_capacity 1];memcpy(_str, s._str, s._size 1);}赋值运算符重载 在实现赋值运算符重载时也存在深浅拷贝的问题我们当然可以像上面的拷贝构造那样申请一块空间然后完成拷贝但是那样的写法有点麻烦于是就有了现代版本 现代版本的参数类型为string而不是引用这就使得string对象在传参时会生成一个临时对象我们将这个临时对象与要替换的对象*this互换就实现了将一个对象赋值到了*this最后返回*this即可临时对象会在函数栈帧销毁时析构。 这里的交换需要用到swap函数这个函数后面会实现 //string operator(const string s); //老版本string operator(string s){swap(s);return *this;}析构函数 析构函数只需使用delete[] 释放_str指向的堆中的空间即可还可以顺带将_size 与_capacity置0 ~string(){_size 0;_capacity 0;delete[] _str;}迭代器 前面提到过string的迭代器就是原生指针所以string中的 iterator就是char*const_iterator 就是const char* 我们只需要使用typedef将char*与const char* 重命名即可 typedef char* iterator;typedef const char* const_iterator;需要注意的是因为在string类外也需要使用迭代器所以这样的重命名应在pubilc中。 begin begin获取的是字符序列首元素的地址有两个重载版本即对于非const对象返回iterator对于const对象返回const_iterastor首元素的地址就是_str。 需要注意的是const版本需要使用const修饰this指针 string::iterator begin(){return _str;}string::const_iterator begin() const{return _str;}end end获取的是字符序列最后一个元素下一个位置的地址有两个重载版本即对于非const对象返回iterator对于const对象返回const_iterastor最后一个元素下一个位置的地址就是_str _size。 string::iterator end(){return _str _size;}string::const_iterator end() const{return _str _size;}容量 size、capacity、empty 这三个成员函数的实现逻辑类似 size用于获取string对象中字符序列的元素个数返回_size即可 capacity用于获取string对象的容量返回_capacity即可 empty用于判断string对象是否为空若为空返回true否则返回false size_t size() const{return _size;}size_t capacity() const{return _capacity;}bool empty() const{if (_size 0){return true;}return false;}reserve reserve用于修改string对象的容量这个函数只有一个参数n表示要扩容到多少个char。 reserve在扩容时当n小于当前对象的容量时reserve会将容量调整为比n大的值所以在模拟实现时当n小于容量时将不做任何事。所以先判断n是否大于_capacity C中使用new不能像realloc一样实现扩容必须使用new新开一块空间开空间时由于_capacity没有包括\0所以要开n 1个char的空间 再将原空间中的数据拷贝到新空间然后释放原空间 然后使_str指向新空间 最后将_capacity的值改为n void reserve(size_t n){if (n _capacity) {char* newstr new char[n 1]{ 0 };memcpy(newstr, _str, _size 1);delete[] _str;_str newstr;_capacity n;}}resize resize用于修改string对象中字符序列的个数当参数n小于size就删大于size则用指定的字符c补足。 首先判断当n大于_size的值时就需要扩容复用reserve扩容至n 然后循环将下标为_size到n - 1位置的元素改为指定的c 最后在末尾加上\0并更新_size的值 当n小于_size的值时直接在下标为n的位置加上\0并更新_size即可 void resize(size_t n, char c){if (n _size){if (n _capacity){reserve(n _size);}for (size_t i _size; i n; i){_str[i] c; //这里的[]是访问数组元素并非运算符重载的调用所以不会越界}_size n;_str[_size] \0;}else{_size n;_str[_size] \0;}}访问元素 operator[] 通过重载[]可以实现像数组下标一样访问string对象中字符序列的元素有两个重载版本即对普通对象与const对象。函数有一个参数index即要访问元素的下标。 首先assert判断参数index是否越界 然后返回_str[index]即可 char operator[](size_t index){assert(index _size);return _str[index];}const char operator[](size_t index) const{assert(index _size);return _str[index];}修改 insert insert实现将一个字符或字符串插入到string对象的pos位置实现两个重载版本即在pos位置插入一个字符与一个字符串 插入字符 首先assert判断pos是否越界pos为无符号整数所以只需要判断是否大于_size即可 然后当_size等于_capacity时即空间已满需要扩容 扩容时当_capacity的值为0时扩容到4不为0时二倍扩容 然后就需要循环将pos位置后的数据全部向后移动需要注意的是循环的终止条件当pos为0时若end的初始值为_size且为end给end 1赋值循环的终止条件就为end pos。而pos为size_t当end与pos比较时会转化为size_t而永远不可能小于0故end的初始值为_size 1将end 1给前赋值终止条件就为end pos 最后将c填充到pos位置并更新_size string insert(size_t pos, char c){assert(pos _size);if (_size _capacity){if (_capacity ! 0){reserve(2 * _capacity);}else{reserve(4);}}size_t end _size 1;while (end pos) //pos为size_t当end与pos比较时会转化为size_t而永远不可能小于0.故将end1后给前赋值{_str[end] _str[end - 1];--end;}_str[pos] c;_size;return *this;}插入字符串 插入字符串的逻辑与插入字符类似 首先判断pos是否越界并判断是否需要扩容当容量小于_size len时就需要扩容len 为插入字符串的长度这里可以直接调用reserve因为reserve中会判断参数是否大于原容量 然后将pos位置后的数据全部向后移动len个位置依旧需要注意终止条件必须为 end pos len - 1 若为end poslen时当在0位置插入一个空串就会导致死循环因为无符号整型不可能小于0。当为end pos len - 1时遇到上面的情况0 - 1为 -1对无符号整型就是一个很大的数将直接不进入循环 然后循环将字符串中的数据拷贝到pos位置并更新_size string insert(size_t pos, const char* str){assert(pos _size);size_t len strlen(str);reserve(len _size);size_t end _size len;while (end pos len - 1) //写成end poslen就会有问题在0位置插一个{_str[end] _str[end - len];--end;}for (size_t i 0; i len; i){_str[pos i] str[i];}_size len;return *this;}append append实现在string对象后追加一个字符串 首先判断str是否为空指针并判断是否需要扩容当newlenth _capacity时即需要扩容当然也可以交给reserve中判断 然后使用strcpy将str中的数据拷贝到_str _size的后面这里不需要使用memcpy因为这里的字符串拷贝就是按照\0为结束标志的 最后更新_size //尾追加void append(const char* str){assert(str);size_t newlenth _size strlen(str);if (newlenth _capacity){reserve(newlenth);}strcpy(_str _size, str);_size newlenth;}push_back push_back用于在string对象末尾添加一个字符 实现时首先判断是否需要扩容与insert插入字符时的逻辑一致 然后将c放在_str的_size位置并更新_size 最后需要手动补上\0 //尾插void push_back(char c){if (_size _capacity){if (_capacity ! 0){reserve(2 * _capacity);}else{reserve(4);}}_str[_size] c;_size;_str[_size] \0;}operator operator即在string对象的末尾追加数据实现两个重载版本即追加字符与追加字符串 实现时复用append与push_back即可当然上面的append与push_back也可以借助insert实现 string operator(char c){push_back(c);return *this;}string operator(const char* str){append(str);return *this;}erase erase实现删除pos位置上的len个元素 当len等于npos时即将pos位置后全删将pos位置改为\0并更新_size即可npos为无符号整型的-1即一个很大的数 否则就需要循环将pos len位置后的数据全部向前移动 len个位置覆盖原数据实现删除最后更新_size // 删除pos位置上的len个元素并返回string erase(size_t pos, size_t len){if (len npos){_size pos;_str[_size] \0;}for (size_t i 0; i _size - pos; i){_str[pos i] _str[pos len i];}_size - len;return *this;}clear clear即清空string对象中的数据只需要将0位置改为\0并将_size更新为0即可 void clear(){_size 0;_str[_size] \0;}swap swap实现交换两个string对象 在之前的swap函数包括算法库中的swap函数均是通过临时变量的方式交换的。但是对于string对象而言要创建临时对象通过三次赋值来交换的话就会产生三次深拷贝十分影响效率。 在实现交换时其实没有必要出现深拷贝string对象中有_str指向一块空间中存储数据只要交换string对象中的这个存储数据的指针即可实现交换数据所以将string的对象的属性分别实现交换即可交换_size、_capacity、_str即可 void swap(string s){std::swap(_size, s._size);std::swap(_capacity, s._capacity);std::swap(_str, s._str);}比较运算符重载 在实现比较运算符重载时我们其实只需要实现两种即与其他的运算符重载通过复用这两种即可此类函数都需要使用const修饰this以适配const对象 operator operator实现两个string对象的比较当第一个对象小于第二个对象时返回true否则返回false 我们可以for循环逐字节判断循环的终止条件为两个string对象_size的较小值 当遇到对应字符不相等的情况时直接返回true或false 当循环结束说明前面的元素都是相等的。此时哪个对象的_size较大则该对象较大 bool operator(const string s) const{for (size_t i 0; i (_size s._size ? _size : s._size); i){if (_str[i] s._str[i])return true;if (_str[i] s._str[i])return false;}if (_size s._size)return true;elsereturn false;}operator operator用于判断两个string对象是否相等相等返回true否则返回false 当两个string对象的_size不同时直接返回false 然后循环遍历两个对象遇到对应位置不相同的直接返回false 最后出循环说明均相等返回true bool operator(const string s) const{if (_size ! s._size)return false;for (size_t i 0; i _size; i){if (_str[i] ! s._str[i])return false;}return true;}其他 其他函数根据比较的逻辑复用即可 bool operator(const string s) const{if (*this s || *this s)return true;elsereturn false;}bool operator(const string s) const{if (!(*this s))return true;elsereturn false;}bool operator(const string s) const{if (!(*this s))return true;elsereturn false;}bool operator!(const string s) const{if (!(*this s))return true;elsereturn false;}查找 find用于在string对象中查找是否存在某字符或某字符串若存在就返回其第一次出现的位置否则返回npos有两个重载版本即查找字符与查找字符串 查找字符 查找字符时即使用循环从pos位置开始遍历string对象中的数据当遇到与c相等的字符时就返回该位置。若出循环就表示没有找到返回npos // 返回c在string中第一次出现的位置size_t find(char c, size_t pos) const{assert(pos _size);for (size_t i pos; i _size; i){if (_str[i] c){return i;}}return npos;}查找字符串 在string对象中查找字符串时可以使用之前C语言时学过的strstr函数用于查找字串。当第2个参数为第1个参数的子串时返回在其中的第一个位置的地址否则返回空指针 首先assert判断s是否为空指针以及pos是否越界 然后调用strstr第一个参数为_str第二个参数为s并创建一个指针pchar来接收返回值 当pchar为空时返回npos当pchar - _str的值不小于pos时返回该差否则返回npos // 返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos) const{assert(s);assert(pos _size);char* pchar strstr(_str, s);if (pchar nullptr){return npos;}if ((size_t)(pchar - _str) pos){return pchar - _str;}return npos;}非成员函数 非成员函数中只实现流插入与流提取运算符的重载operator与operator 在之前的日期类实现中我们使用友元函数实现在这两个函数中可以访问对象的属性。但在string类中由于之前实现过访问元素的operator[]所以可以不使用友元就可以实现在这两个函数中访问string对象的元素 operator 在operator中 我们只需要将string对象s中的元素依次流入到ostream的对象_cout即可 ostream operator(ostream _cout, const string s){for (size_t i 0; i s.size(); i){_cout s[i];}return _cout;}operator 在向内存中输入数据时我们当然可以逐字符的但是这样会造成多次的扩容而影响效率。 我们可以直接创建一个128字节的数组来转存数据当在这个数组中存满后再将这个数组中的数据到string对象中然后清空数据继续接收数据等到全部接收完毕后将其中剩余的元素再****到string对象后即可 istream operator(istream _cin, string s){s.clear();char ch _cin.get();//清除缓冲区中的空格与换行while (ch || ch \n){ch _cin.get();}//定义一个128的字符数组char temp[128] { 0 };int i 0;while (ch ! ch ! \n){if (i 127){s temp;i 0;}temp[i] ch;i;ch _cin.get();}//如果i0 即temp中还有数据将其转存即可if (i 0){temp[i] \0;s temp;}return _cin;}源码概览 #includeiostream #includecassert using namespace std;namespace qqq {class string{public:typedef char* iterator;typedef const char* const_iterator;public:string(const char* str ){assert(str);_size strlen(str);_capacity _size;_str new char[_capacity 1];memcpy(_str, str, _size 1);}string(const string s){_size s._size;_capacity s._capacity;_str new char[_capacity 1];memcpy(_str, s._str, s._size 1);}//string operator(const string s); //老版本string operator(string s){swap(s);return *this;}~string(){_size 0;_capacity 0;delete[] _str;}//// iteratorstring::iterator begin(){return _str;}string::iterator end(){return _str _size;}string::const_iterator begin() const{return _str;}string::const_iterator end() const{return _str _size;}/// modify// 在pos位置上插入字符c/字符串str并返回string insert(size_t pos, char c){assert(pos _size);if (_size _capacity){if (_capacity ! 0){reserve(2 * _capacity);}else{reserve(4);}}size_t end _size 1;while (end pos) //pos为size_t当end与pos比较时会转化为size_t而永远不可能小于0.故将end1后给前赋值{_str[end] _str[end - 1];--end;}_str[pos] c;_size;return *this;}string insert(size_t pos, const char* str){assert(pos _size);size_t len strlen(str);reserve(len _size);size_t end _size len;while (end pos len - 1) //写成end poslen就会有问题在0位置插一个{_str[end] _str[end - len];--end;}for (size_t i 0; i len; i){_str[pos i] str[i];}_size len;return *this;}// 删除pos位置上的元素并返回string erase(size_t pos, size_t len){if (len npos){_size pos;_str[_size] \0;}for (size_t i 0; i _size - pos; i){_str[pos i] _str[pos len i];}_size - len;return *this;}//尾插void push_back(char c){if (_size _capacity){if (_capacity ! 0){reserve(2 * _capacity);}else{reserve(4);}}_str[_size] c;_size;_str[_size] \0;}string operator(char c){push_back(c);return *this;}//尾追加void append(const char* str){assert(str);size_t newlenth _size strlen(str);if (newlenth _capacity){reserve(newlenth);}strcpy(_str _size, str);_size newlenth;}string operator(const char* str){append(str);return *this;}void clear(){_size 0;_str[_size] \0;}void swap(string s){std::swap(_size, s._size);std::swap(_capacity, s._capacity);std::swap(_str, s._str);}const char* c_str() const{return _str;}/// capacitysize_t size() const{return _size;}size_t capacity() const{return _capacity;}bool empty() const{if (_size 0){return true;}return false;}void resize(size_t n, char c){if (n _size){if (n _capacity){reserve(n _size);}for (size_t i _size; i n; i){_str[i] c; //这里的[]是访问数组元素并非运算符重载的调用所以不会越界}_size n;_str[_size] \0;}else{_size n;_str[_size] \0;}}void reserve(size_t n){if (n _capacity){char* newstr new char[n 1]{ 0 };memcpy(newstr, _str, _size 1);//strcpy(newstr, _str);delete[] _str;_str newstr;_capacity n;}}/// accesschar operator[](size_t index){assert(index _size);return _str[index];}const char operator[](size_t index) const{assert(index _size);return _str[index];}///relational operatorsbool operator(const string s) const{for (size_t i 0; i (_size s._size ? _size : s._size); i){if (_str[i] s._str[i])return true;if (_str[i] s._str[i])return false;}if (_size s._size)return true;elsereturn false;}bool operator(const string s) const{if (_size ! s._size)return false;for (size_t i 0; i _size; i){if (_str[i] ! s._str[i])return false;}return true;}bool operator(const string s) const{if (*this s || *this s)return true;elsereturn false;}bool operator(const string s) const{if (!(*this s))return true;elsereturn false;}bool operator(const string s) const{if (!(*this s))return true;elsereturn false;}bool operator!(const string s) const{if (!(*this s))return true;elsereturn false;}// 返回c在string中第一次出现的位置size_t find(char c, size_t pos) const{assert(pos _size);for (size_t i pos; i _size; i){if (_str[i] c){return i;}}return npos;}// 返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos) const{assert(s);assert(pos _size);char* pchar strstr(_str, s);if (pchar nullptr){return npos;}if ((size_t)(pchar - _str) pos){return pchar - _str;}return npos;}private:char* _str;size_t _capacity;size_t _size;const static size_t npos;};const size_t string::npos -1;ostream operator(ostream _cout, const string s){for (size_t i 0; i s.size(); i){_cout s[i];}return _cout;}istream operator(istream _cin, string s){s.clear();char ch _cin.get();//清除缓冲区中的空格与换行while (ch || ch \n){ch _cin.get();}//定义一个128的字符数组char temp[128] { 0 };int i 0;while (ch ! ch ! \n){if (i 127){s temp;i 0;}temp[i] ch;i;ch _cin.get();}//如果i0 即temp中还有数据将其转存即可if (i 0){temp[i] \0;s temp;}return _cin;} }总结 到此关于string类的模拟实现就介绍完了 相信通过模拟实现string类可以使我们更深入地理解string 如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题欢迎大家在评论区提出 如果本文对你有帮助希望一键三连哦 希望与大家共同进步哦
http://wiki.neutronadmin.com/news/48909/

相关文章:

  • 旅游订票网站开发公司商标设计
  • 蓝色科技企业网站模板android开发基础教程
  • 网站建站建设多少钱软件实施工资一般多少
  • 网站轮播图能用什么软件做dw做网站怎么排版
  • 2018年怎么做网站排名网站推广的优点
  • 网站备案信息查询申请表学校网站模板大全
  • 石狮网站设计公司中国工信部网站备案
  • 工具刷网站排刷排名软件百度怎么把自己网站展现在百度
  • 用xp做网站是否先搭建iiswordpress对php版本要求
  • 福田做商城网站建设找哪家公司好合肥高端网站
  • 网站托管就业wordpress图片无法读取
  • 网站标题的优化知名企业网站人才招聘情况如何
  • 网站建设与管理收获旅游搭建网站
  • 青岛专业制作网站北京手机网站设计
  • 手机系统seo推广编辑
  • 招聘网站上找在家做万网 速成网站
  • 钓鱼网站怎么制作htmlWordPress文章投票
  • 建网站要备案深圳坪山高铁站
  • 中国最大免费wap网站diy小程序开发平台
  • 江镇做包子网站合肥市城乡城乡建设局网站
  • 网站为什么要维护陕西交通建设集团西镇分公司网站
  • jq网站登录记住密码怎么做企业网站的一般要素包括哪些
  • 网站设计的素材有哪些网站上传系统
  • 东莞集团网站建设规定学做网站需要学那些程序
  • 网站根目录 设置网站域名解析到了空间 但空间未绑定此域名
  • 建设网站要求dede网站微信分享封面
  • 兰州市城乡建设局网站公布的信息吴中区网站建设技术
  • 网站建设设计师手机网站与PC网站
  • 新民电商网站建设价格咨询附近的招聘工作
  • 在哪里做百度网站wordpress 米课