C++ string容器类实现
2015-07-23 16:23
127 查看
最近想学习一下C++ STL中容器类的实现,就先研究最简单的string容器类,通过学习简单的,达到管中窥豹,举一反三的目的,话不多说,直接来干货,写得不好,望大家多多交流和指教。
代码如下:
自我总结需要改进的地方:
(1)每一次大小改变都重新申请内存,导致效率不高,同时造成内存碎片。[改进:申请一块内存,多申请一些,多余的内存作为保留字节]
(2)string的成员函数参数大部分都是字符串类型,应该还有输入迭代器类型的很多重载函数,我也没有实现。
(3)有部分成员函数为实现,比如查找只实现了三个,还有像capacity(),reserve()没有实现,也可以添加实现。
(4)函数加保护,超出范围是抛出异常还是报错,没实现。[本想抛出异常的,但是还不太会,就没做]
代码如下:
<span style="font-size:18px;">// MyString.cpp : 定义控制台应用程序的入口点。 // /***************************************** **功能:自己实现C++ STL的string容器类 **作者:谢凡凡 **时间:2015-07-21 02:20 *****************************************/ #include "stdafx.h" #include <iostream> #include <iomanip> //后边用到函数setw设置域宽,所以包含该头文件 using namespace std; //自己尝试写的一个string容器类 class MyString { friend ostream& operator<<(ostream&,MyString&); //输出运算符重载,友元函数 friend istream& operator>>(istream&,MyString&); //输入运算符重载 public: MyString(const char* str = NULL); //默认构造函数,含有一个默认参数 MyString(const MyString& other); //拷贝构造函数,拷贝了数据,所以说深拷贝 MyString& operator=(const MyString& other); //重载赋值运算符 MyString operator+(const MyString& other) const; //重载加号运算符 bool operator==(const MyString& ); //operator== bool operator<(const MyString& ); //operator< char& operator[](int); //operator[] size_t size() {return strlen(m_data);} MyString& append(const MyString& other); //在尾部插入 MyString& insert(unsigned int ipos,const char *); //任意位置插入 MyString& replace(unsigned int ipos,unsigned int num,const char *); //替换操作 MyString& erase(unsigned int start,unsigned int final); //删除函数 int find(const char* stem,int ipos = 0); //查找函数 int find_first_of(const char* stem,int ipos = 0); //查找字符串中第一个在指定串中出现的字符位置 int rfind(const char *stem,int ipos = -1); //反向查找,从左往右数ipos位做为起始的位置,然后从右往左匹配,找到第一个返回位置 int npos; //查询标志 表示字符串查询失败 //下边写迭代器类 class Iterator { char *init; public: inline Iterator(char* init) {this->init = init;} //构造函数 inline bool operator!=(Iterator& it) {return this->init != it.init;} //迭代器的几个运算符重载 inline void operator++(int){init = init + 1;} inline char operator*() {return *init;} }; char* Begin() {return m_data;} //获得迭代器的起始位置 char* End(){return m_end;} //获得迭代器的尾后位置 ~MyString(); //析构函数 private: char* m_data; //指向动态内存的指针 char* m_end; //尾后指针 }; inline MyString::MyString(const char* str) //默认构造函数设为内联 不掉用 直接替换 { if (!str) { m_data =NULL; m_end = NULL; } else { m_data = new char[strlen(str)+1]; m_end = m_data + strlen(str); //尾后迭代器位置 strcpy(m_data,str); } npos = -1; } inline MyString::MyString(const MyString& other) //拷贝函数 { if (!other.m_data) //在类的成员函数内可以访问同种对象的私有数据(同种类是友元关系) { m_data = NULL; m_end = NULL; } else { m_data = new char[strlen(other.m_data)+1]; m_end = m_data + strlen(other.m_data); strcpy(m_data,other.m_data); } npos = -1; } inline MyString& MyString::operator=(const MyString& other) //赋值运算符 { if (this != &other) //注意,赋值运算符考虑自赋值 { delete [] m_data; m_end = m_data; if (!other.m_data) { m_data = NULL; m_end = NULL; } else { m_data = new char[strlen(other.m_data)+1]; m_end = m_data + strlen(other.m_data); strcpy(m_data,other.m_data); } } return *this; //this指针的引用为类对象 } inline MyString MyString::operator+(const MyString& other)const //加号重载 { //考虑多种情况 MyString newString; //加号重载,返回一个值,所以用一个临时变量返回 if (!other.m_data) { newString = *this; } else if (!m_data) { newString = other; } else { newString.m_data = new char[strlen(m_data) + strlen(other.m_data) +1]; newString.m_end = newString.m_data + strlen(m_data) + strlen(other.m_data); strcpy(newString.m_data,m_data); strcat(newString.m_data,other.m_data); } return newString; } inline bool MyString::operator==(const MyString& other) { if (strlen(other.m_data) != strlen(m_data)) { return false; } else { return strcmp(other.m_data,m_data)?false:true; } } inline bool MyString::operator<(const MyString& other) //operator< { if (strlen(m_data) == 0 && strlen(other.m_data) != 0) { return true; } else if (strlen(m_data) != 0 && strlen(other.m_data) == 0) { return false; } else if (strlen(m_data) == 0 && strlen(other.m_data) == 0) //表示两个都为空 { return false; } int iIndex = 0; while (m_data[iIndex] && other.m_data[iIndex]) //相同长度逐个比较字符 { if (m_data[iIndex] < other.m_data[iIndex]) { return true; } else if (m_data[iIndex] > other.m_data[iIndex]) { return false; } else { ++iIndex; } } if (!m_data[iIndex] && other.m_data[iIndex]) //第一个字符串比第二个字符串短 但前边相同 eg: xiefanfan xiefanfanaa { return true; } else { return false; } } inline char& MyString::operator[](int num) { if (num < 0 || num >= strlen(m_data)) { cout<<"string subscript out of range"<<endl; } if (num>=0 && num<strlen(m_data)) { return m_data[num]; } } ostream& operator<<(ostream& os,MyString& mstem) //友元函数,表示该函数不是该类的成员,但是可以操作类的私有数据 { os<<mstem.m_data; //不要添加格式控制符,只做输出 return os; //return支持连续<< } istream& operator>>(istream& is,MyString& mstem) { char temp[255]; //临时缓冲空间 is>>setw(255)>>temp; mstem = temp; //使用赋值运算符 return is; //return支持连续>> } MyString::~MyString() //析构函数 { if (m_data) { delete [] m_data; m_data = NULL; m_end = NULL; } } MyString& MyString::append(const MyString& other) //在尾部插入 参考operator+函数 { MyString newString; //申请一个临时空间 将原始字符串保存起来 if (!other.m_data) { return *this; } else if (!m_data) { m_data = new char[strlen(other.m_data) + 1]; m_end = m_data + strlen(other.m_data); strcpy(m_data,other.m_data); return *this; } else { newString = *this; m_data = new char[strlen(newString.m_data) + strlen(other.m_data) +1]; m_end = m_data + strlen(newString.m_data) + strlen(other.m_data); strcpy(m_data,newString.m_data); strcat(m_data,other.m_data); return *this; } } MyString& MyString::insert(unsigned int ipos,const char *stem) //任意位置插入函数 { MyString newString; int iIndex; if (ipos >= 0 && ipos < strlen(m_data)) //ipos在范围内部 { newString.m_data = new char[strlen(m_data) + strlen(stem) +1]; //申请空间 newString.m_end = m_data + strlen(m_data) + strlen(stem); for (iIndex = 0;iIndex < strlen(m_data) + strlen(stem);++iIndex) { if (iIndex < ipos) //拷贝原始串 ipos前的数据 { newString.m_data[iIndex] = m_data[iIndex]; } else { if (iIndex >= ipos && iIndex < (ipos + strlen(stem))) //添加子串 { newString.m_data[iIndex] = stem[iIndex - ipos]; } else //添加原来字符串后边的串 { newString.m_data[iIndex] = m_data[iIndex - strlen(stem)]; } } } newString.m_data[iIndex] = NULL; //最后一位置空 表示字符串结束 } *this = newString; return *this; } MyString& MyString::replace(unsigned int ipos,unsigned int num,const char *stem) //替换操作 { MyString newString; //临时缓存字符串 int iIndex; if (ipos >= 0 && ipos < strlen(m_data) ) { int iNewlen = strlen(m_data) + strlen(stem) - num; //新的长度 newString.m_data = new char[iNewlen + 1]; newString.m_end = m_data + iNewlen; for (iIndex = 0;iIndex < iNewlen;++iIndex) { if (iIndex < ipos) //拷贝ipos索引前的字符 { newString.m_data[iIndex] = m_data[iIndex]; } else if (iIndex >= ipos && iIndex < ipos + strlen(stem)) //拷贝替换的串 { newString.m_data[iIndex] = stem[iIndex - ipos]; } else //拷贝原串剩余的部分 { newString.m_data[iIndex] = m_data[iIndex - strlen(stem) + num]; } } } newString.m_data[iIndex] = '\0'; //字符串最后置为0 *this = newString; return *this; } /////////////////////////////此处应该用的迭代器///////////////////////////////////////////// MyString& MyString::erase(unsigned int start,unsigned int final) //删除函数 { if (start >= 0 && start < strlen(m_data) && final >= 0 && final < strlen(m_data) && start <= final) { int iIndex; for (iIndex = final;iIndex < strlen(m_data);++iIndex ) { m_data[iIndex - final + start] = m_data[iIndex]; //后边覆盖前边 } m_data[iIndex - (final - start)] = '\0'; m_end = m_data + iIndex - (final - start); } return *this; } int MyString::find(const char* stem,int ipos ) //字串查找函数 { if (ipos + strlen(stem) > strlen(m_data)) //超出范围 { return npos; } for (int iIndex = ipos;iIndex < strlen(m_data) - strlen(stem);++iIndex) //在长的串中匹配指定的串 若要快速匹配 可以用KMP算法 { int jval = 0; while (stem[jval] && stem[jval] == m_data[iIndex + jval]) //逐位匹配 { jval++; } if (jval >= strlen(stem)) { return iIndex; } } return npos; } int MyString::find_first_of(const char* stem,int ipos) //查找字符串中第一个在指定串中出现的字符位置 { int length = strlen(m_data); int iIndex; for ( iIndex = 0;iIndex < length;++iIndex) { for (int iIndex1 = 0;iIndex1 < strlen(stem);++iIndex1) { if (m_data[iIndex] == stem[iIndex1]) //如果匹配上一个字符,返回坐标 { return iIndex; } } } if (iIndex >= length) { return npos; } } int MyString::rfind(const char *stem,int ipos) //反向查找 { if (ipos == npos) { ipos = strlen(m_data); } for (int iIndex = ipos;iIndex >= 0;--iIndex) { int slen = strlen(m_data); //原串长度 int slen1 = strlen(stem); //匹配串长度 if ((slen - iIndex) >= slen1) //当前字符后边字符数大于等于带匹配串 { int tem = 0; while (m_data[iIndex + tem] == stem[tem] && tem < slen1) //逐项匹配 { ++tem; } if (tem >= slen1) { return iIndex; } } } return npos; //如果上边没有匹配上,表示不存在匹配项 } int _tmain(int argc, _TCHAR* argv[]) { MyString str("fasfd"); str.erase(0,2); MyString::Iterator start = str.Begin(); MyString::Iterator end = str.End(); while(start != end) { cout<<*start<<endl; start++; } return 0; }</span>每一个函数经过测试,功能基本上跑通了,但是压力测试可能过不了。
自我总结需要改进的地方:
(1)每一次大小改变都重新申请内存,导致效率不高,同时造成内存碎片。[改进:申请一块内存,多申请一些,多余的内存作为保留字节]
(2)string的成员函数参数大部分都是字符串类型,应该还有输入迭代器类型的很多重载函数,我也没有实现。
(3)有部分成员函数为实现,比如查找只实现了三个,还有像capacity(),reserve()没有实现,也可以添加实现。
(4)函数加保护,超出范围是抛出异常还是报错,没实现。[本想抛出异常的,但是还不太会,就没做]
相关文章推荐
- c++对象模型
- 栈帧详解
- 读书笔记MoreEffectiveC++(7)
- C语言--指针
- C++中的指针和引用
- HDU 1421 搬寝室
- 【C++】用C++写个方法,打印输入文件的最后K行
- 读书笔记MoreEffectiveC++(6)
- C++ auto 与 register、static 关键字 浅析
- 【C++】模板
- C++ 深入理解 auto 关键字
- c++类内接口调用其它函数传递成员指针问题(以二叉树举例)
- C++ Set & MultiSet
- 读书笔记MoreEffectiveC++(五)
- C++模拟登录web的一点点体会
- C++/C试题
- (转)值得推荐的C/C++框架和库
- C++ List的用法(整理)
- 使用C语言计算utf-8字符串长度
- C++之带有默认参数值的构造函数