字符串String类的完整实现 C++程序设计语言第11章

这是一个很有趣的练习。它让我了解了标准库String类的实现,并且增强了我对面向对象编程的理解。这个String类的对象基于采用引用计数的String类表示(Srep),多个String之间将会共享同一个表示。并且在写时仍然采用值语义(即,对一个String的操作不会影响到另一个String),这使用了一种叫“写时复制”的计数,只在对String类进行修改时再复制String类对象。这个良好的策略将会使得用户即可以使用值语义的String字符串又可以不用负担过大的内存开销(因为保存同一内容的String会共享同一表示)。

还有一个很关键的部分是Cref这个成员类。这个类的作用相当于一个char&,在调用String的下标操作符时返回。然而,为什么不直接返回一个char&呢?因为如果直接返回char&的话就允许了用户对String的随意修改,而这与String的设计意图是矛盾的。String的设计意图是在修改String时对String进行复制(与原来共享的表示分离)。也就是说,我们并不想返回一个低级表示给用户随意使用。在这种情况下我们定义了一个Cref类。这个类将在用户读取String的[]下标内容时转换为一个char,而在用户修改这个字符(例如,String[0]='a')时复制String的表示(通过定义赋值操作符)。

这些练习中最困难的是设计String类使得子串可以用在赋值的左边。我仔细想了想这里也应该运用相同的策略:返回一个Sref类型保存绑定到String的子串的引用。在读取时返回一个String,在修改时对原String进行复制。

我还定义了一个find(const String&)函数。注意到我在find函数中并没有进行逐个的char比较,而是调用了operator==比较参数和目标String的子串。这也是C++程序设计语言一直强调的,尽量少操作对象的直接表示。

输入操作符operator>>我的实现很简陋,创建一个大小为20的char数组保存输入。我无法想出一个更好的实现。如果大家有更好的实现方法,希望能留言建议,谢谢!

String.h

//2.(*2) 完成并测试String类。(完成拼接运算符和IO操作符) 
//7.(*2) 为String 类定义一个外部迭代器String_tier。添加一些操作。 
//8.(*1.5) 通过重载()为String类提供一个字串操作。
//9.(×3) 设计String类使得字串可以用在赋值的左边。
//写一个版本允许给串赋的字串长度变化。 
//10.(*2) 为String定义一个操作,产生其值的C字串表示。 
//11.(*2.5) 为String定义和实现一个简单的模式匹配功能函数。
//(我实现的是一个find函数。) 

#ifndef STRING_H
#define STRING_H

#include <iostream>
#include <cstring>
class String{
	struct Srep{
    	char* s;
    	int sz;
    	int n;
        
        Srep(int nsz,const char* p):
            sz(nsz),n(1),s(new char[sz+1]){strcpy(s,p);}
        ~Srep(){delete[] s;}
        
        Srep* get_own_copy()
    	{
    		if(n==1) return this;
    		--n;
    		return new Srep(sz,s);
    	}
    	void assign(int nsz,const char* p)
    	{
    		if(sz!=nsz){
    			delete[] s;
    			sz=nsz;
    			s=new char[sz+1];
    		}
    		strcpy(s,p);
        }
    private:
        Srep(const Srep&);
        Srep& operator=(const Srep&);
    };
    Srep* rep;
public:
    friend class String_iter;

    class Cref{
    	friend class String;
	    String& s;
	    int i;
	    Cref(String& ss,int ii):s(ss),i(ii){}
    public:
        operator char() const{return s.read(i);}
        void operator=(char c){s.write(i,c);}
    };
    class Sref{
        friend class String;
        String& s;
        int nbeg,nend;
        Sref(String& ss,int b,int e):s(ss),nbeg(b),nend(e){}
    public:
        operator String() const
		    {return static_cast<const String&>(s)(nbeg,nend);}
        void operator=(const String& ss)
        {
        	if(nend-nbeg==ss.size()-1){
              	s.rep=s.rep->get_own_copy();
            	for(int ix=nbeg;ix<=nend;++ix)
            	    s.rep->s[ix]=ss.rep->s[ix];
            }else{
            	//这里的方法未必要一样。只要可行即可。 :
            	String left=
				    nbeg==0?"":static_cast<const String&>(s)(0,nbeg-1);
            	String right=
				    nend==s.rep->sz-1?"":static_cast<const String&>(s)(nend+1,s.rep->sz-1);
            	s=String();
				((const_cast<String&>(s)+=left)+=ss)+=right;
            }
        }
    };
    class Range{};
    
    String():rep(new Srep(0,"")){}
    String(const char* s):rep(new Srep(strlen(s),s)){}
    String(const String& x)
    {
    	++x.rep->n;
    	rep=x.rep;
    }
    String& operator=(const char*);
    String& operator=(const String&);
    
    String& operator+=(const char* s)
	{
	    rep=rep->get_own_copy();
		strcat(rep->s,s);
		rep->sz+=strlen(s);
		return *this;
	}
    String& operator+=(const String& x)
	{
	    rep=rep->get_own_copy();
		strcat(rep->s,x.rep->s);
		rep->sz+=x.rep->sz;
		return *this;
	}
    
    friend std::ostream& operator<<(std::ostream& os,const String& x)
        {return os<<x.rep->s;}
    friend std::istream& operator>>(std::istream&,String&);
    
    friend bool operator==(const String& x,const char* s)
        {return strcmp(x.rep->s,s)==0;}
    friend bool operator==(const String& x,const String& y)
        {return strcmp(x.rep->s,y.rep->s)==0;}
    friend bool operator!=(const String& x,const char* s)
        {return strcmp(x.rep->s,s)!=0;}
    friend bool operator!=(const String& x,const String& y)
        {return strcmp(x.rep->s,y.rep->s)!=0;}
    
    ~String(){if(--rep->n==0) delete rep;}
    
    void check(int i) const{if(i<0||rep->sz<=i) throw Range();}
    char read(int i) const{return rep->s[i];}
    void write(int i,char c){rep=rep->get_own_copy();rep->s[i]=c;}
    
    int find(const String&) const;
    
    char operator[](int i) const{check(i);return rep->s[i];}
    Cref operator[](int i){check(i);return Cref(*this,i);}
    
    String operator()(int,int) const;
    Sref operator()(int,int);

    const char* c_str() const{return rep->s;}
    int size() const{return rep->sz;}
};
String& String::operator=(const char* s)
{
	if(rep->n==1)
	    rep->assign(strlen(s),s);
    else{
    	--rep->n;
        rep=new Srep(strlen(s),s);
    }
    return *this;
}
String& String::operator=(const String& x)
{
	++x.rep->n;
	if(--rep->n==0) delete rep;
    rep=x.rep;
    return *this;
}
String String::operator()(int nbeg,int nend) const
{
	check(nbeg);check(nend);
	if(nbeg<=nend){
        char *ca=new char[nend-nbeg+2];
        strncpy(ca,rep->s+nbeg,nend-nbeg+1);
        ca[nend-nbeg+1]='\0';
        String ret(ca);
        delete[] ca;
        return ret;
	}else
	    return String("");
}
String::Sref String::operator()(int nbeg,int nend)
{
	check(nbeg);check(nend);
	if(nbeg<=nend){
		return Sref(*this,nbeg,nend);
	}else{
		String tp("");
		String& temp=tp;
	    return Sref(temp,0,0);
	}
}
int String::find(const String& x) const
{
	int pos=0;
	int sz=x.size();
	while(pos+sz<=this->size()&&x!=this->operator()(pos,pos+sz-1))
	    ++pos;
    if(pos+sz<=this->size())
        return pos;
    else
        return -1;
}
String operator+(const String& x,const char* s)
{
	String ret(x);
	ret+=s;
	return ret;
}
String operator+(const String& x,const String& y)
{
	String ret(x);
	ret+=y;
	return ret;
}
std::istream& operator>>(std::istream& is,String& x)
{
	char* s=new char[20];
	is>>s;
	x=s;
	return is;
}
class String_iter{
	mutable int ix;
	String& str;
public:
    String_iter(String& s):str(s),ix(0){}
    char& next()
	{
		str.rep=str.rep->get_own_copy();
	    return str.rep->s[ix++];
	}
    char next() const{return str.rep->s[ix++];}
    
    String_iter& operator++(){++ix;return *this;}
    String_iter operator++(int);
    
    String_iter& operator--(){--ix;return *this;}
    String_iter operator--(int);
};
String_iter String_iter::operator++(int)
{
	String_iter ret(*this);
	++*this;
	return ret;
}
String_iter String_iter::operator--(int)
{
	String_iter ret(*this);
	++*this;
	return ret;
}

#endif

main.cpp

#include <iostream>
#include "String.h"
using namespace std;
int main()
{
	String s("Hello C++");
	cout<<s<<endl;
	cout<<s.find("C++")<<endl;
	s(6,8)="World";
	cout<<s<<endl;
	cout<<s(0,4)<<endl;
	return 0;
}

大家有什么不懂的可以问。乐意解答。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值