自己动手编写string类

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
//子串操作
MyString substr(size_t,size_t); //添加操作
MyString& append(const MyString&);
//插入操作 MyString& insert(size_t,const MyString&); //替换操作 MyString& assign(const MyString&,size_t,size_t); //删除操作 MyString& erase(size_t,size_t);
return strcmp(lhs.p_str,rhs.p_str)>=0; }
需要说明的是,>>操作符重载函数写得比较简单,实际应该考虑很多异常 问题。另临时字符串数组也是无奈之举,或许也可以考虑读取一个字符调用一次 "+="操作符,在 MyString 的设计中,一次"+="操作会涉及内存资源的释放和 再申请,大量执行"+="操作效率不能忍。因此,一个实用的 string 类应涉及" 缓冲区"的概念,内存资源的申请不再和字符串的大小相吻合,这样会提高很多 操作的效率。
const char* c_str();//返回 C 风格字符串的指针
下面该写操作符了,我们知道,string 支持的操作符特别多,这些都是通 过操作符的重载实现的。
//读写操作符
friend ostream& operator<< (ostream&,const MyString&); friend istream& operator>> (istream&,MyString&); //‘+’操作符
return strcmp(lhs.p_str,rhs.p_str)<=0; } bool operator>(const MyString& lhs,const MyString& rhs) {
return strcmp(lhs.p_str,rhs.p_str)>0; } bool operator>=(const MyString& lhs,const MyString& rhs) {
char temp[100];//暂存字符串 if(in>>temp) {
delete[] str.p_str; str.strLength = strlen(temp); str.p_str = new char[str.strLength+1]; strcpy(str.p_str,temp); } return in; } //下标操作符 char& MyString::operator [](const size_t index) { assert(index>=0 && index<=strLength); return p_str[index]; } //下标操作符(const 情况) const char& MyString::operator [](const size_t index)const { assert(index>=0 && index<=strLength);
自己动手编写 string 类
题记:人们对事物的恐惧往往源自不了解,如果你能把它写出来,还怕不会用 吗?
对于那些对 C++标准库中的 string 不甚了解的读者来说,这篇文章的名称 可 能 会 引 起 一 些 混 淆 。 标 准 库 中 的 string 并 不 是 一 个 独 立 的 类 , 而 是 basic_string 模板类的一个特化版本: typedef basic_string<char, char_traits<char>, allocator<char> > string;
//'+='操作符 MyString& MyString::operator+=(const MyString& str) {
if(this == &str) {
MyString copy(str); return *this+=copy; } strLength += str.strLength; char* p_old = p_str; p_str = new char[strLength+1]; strcpy(p_str,p_old); delete[] p_old; strcat(p_str,str.p_str);
return p_str[indexFra Baidu bibliotek; }
//'+'操作符的重载 MyString operator+(const MyString& lhs,const MyString& rhs) {
MyString ret; ret.strLength = lhs.strLength + rhs.strLength; ret.p_str = new char[ret.strLength+1]; strcpy(ret.p_str,lhs.p_str); strcat(ret.p_str,rhs.p_str); return ret; }
MyString::MyString(const size_t len,const char ch) {
strLength = len; p_str = new char[strLength+1]; *(p_str+strLength)='\0'; strset(p_str,ch); }
MyString::~MyString() {
//赋值操作符 MyString& MyString::operator=(const MyString& str) {
if(this!=&str) {
if(strLength<str.strLength) {
delete[] p_str; p_str = new char[str.strLength+1]; } strLength = str.strLength; strcpy(p_str,str.p_str); } return *this; }
char& operator[] (const size_t); const char& operator[] (const size_t)const; //赋值操作符
MyString& operator=(const MyString&); //'+='操作符
MyString& operator+=(const MyString&);
class MyString {private:
size_t strLength; char* p_str; };
下面我们来声明成员函数,当然,还有一些非成员函数。 想一想我们定义一个 string 变量有哪几种方式,一般情况下,以下四种方 式比较常见:
//调用默认构造函数 string s1;
//将 s2 初始化为 s1 的一个副本 string s2(s1); or string s2=s1;
return strcmp(lhs.p_str,rhs.p_str)!=0; } bool operator<(const MyString& lhs,const MyString& rhs) {
return strcmp(lhs.p_str,rhs.p_str)<0; } bool operator<=(const MyString& lhs,const MyString& rhs) {
strLength = str.strLength; p_str = new char[strLength+1]; strcpy(p_str,str.p_str); }
MyString::MyString(const char* str) {
if(str==NULL) return;
strLength = strlen(str); p_str = new char[strLength+1]; strcpy(p_str,str); }
//将 s3 初始化为一个字符串字面值副本 string s3("hello"); or string s3="hello"; //将 s4 初始化为字符'a'的 n 个副本 string s4(n,'a');
下面给出相应的声明: //构造函数
MyString(); MyString(const MyString&); MyString(const char*); MyString(const size_t,const char);
类中存在指针数据成员,我们当然需要自己定义一个析构函数。
//析构函数 ~MyString();
一些基本的属性。
size_t length();//字符串的长度 bool empty();//字符串是否为空
string 中有个 c_str()成员函数,返回 C 风格字符串的指针,我们也加上这 个函数。
有几个问题需要说明。 1、IO 操作符不可以定义为类的成员函数,否则,左操作数只能是该类类型的对 象。
MyString s; s<<cout;
这你能忍? 2、算术和关系操作符一般情况下应定义为非成员函数,它们并不会改变操作数 的状态。 3、上述操作符既为非成员函数,又要访问类的私有数据成员,所以将它们设为 类的友元。 4、下标操作符定义了两个,第二个是对应类对象是 const 的情况,否则,类的 const 对象将无法使用下标。 最后,再写一些操作函数。标准库 string 的操作函数为数众多,且存在大量的 重载版本。这里出于篇幅考虑,选择几个代表性的函数来实现。
我们今天要做的事情是,模仿标准库 string 的行为,编写一个属于自己的 简单的 string 类。为了与标准库中的 string 相区分,我们将自己编写的类命名 为 MyString。
声明篇
数据成员方面我们需要一个 char 型指针来保存字符串,还需要一个 size_t 型变量来保存字符串的长度。显然,它们是应该被封装的,我们将它们的权限设 置为 private。
return p_str; }
操作符的重载:
//输出操作符
ostream& operator<< (ostream& out,const MyString& str) {
if(str.p_str!=NULL) out<<str.p_str;
return out; }
//输入操作符 istream& operator>>(istream& in,MyString& str)// {
delete[] p_str; }
几个简单的成员函数
size_t MyString::length()
{ return strLength;
}
bool MyString::empty() {
return strLength==0?true:false; }
const char* MyString::c_str() {
friend MyString operator+(const MyString&,const MyString&); //比较操作符
friend bool operator==(const MyString&,const MyString&); friend bool operator!=(const MyString&,const MyString&); friend bool operator<(const MyString&,const MyString&); friend bool operator<=(const MyString&,const MyString&); friend bool operator>(const MyString&,const MyString&); friend bool operator>=(const MyString&,const MyString&); //下标操作符
至此,MyString 类的声明就告一段落了。
实现篇
类的声明虽然代码篇幅较短,但其是设计一个类的重中之重。声明做得很完 善,实现一般不会困难。下面依据上文声明的次序给出函数的实现。 构造函数和析构函数
MyString::MyString():strLength(0),p_str(NULL){}
MyString::MyString(const MyString& str) {
return *this; }
//比较操作符 bool operator==(const MyString& lhs,const MyString& rhs) {
return strcmp(lhs.p_str,rhs.p_str)==0; } bool operator!=(const MyString& lhs,const MyString& rhs) {
相关文档
最新文档