自己动手编写string类
类中存在指针数据成员,我们当然需要自己定义一个析构函数。
//析构函数 ~MyString();
一些基本的属性。
size_t length();//字符串的长度 bool empty();//字符串是否为空
string 中有个 c_str()成员函数,返回 C 风格字符串的指针,我们也加上这 个函数。
return strcmp(lhs.p_str,rhs.p_str)>=0; }
需要说明的是,>>操作符重载函数写得比较简单,实际应该考虑很多异常 问题。另临时字符串数组也是无奈之举,或许也可以考虑读取一个字符调用一次 "+="操作符,在 MyString 的设计中,一次"+="操作会涉及内存资源的释放和 再申请,大量执行"+="操作效率不能忍。因此,一个实用的 string 类应涉及" 缓冲区"的概念,内存资源的申请不再和字符串的大小相吻合,这样会提高很多 操作的效率。
自己动手编写 string 类
题记:人们对事物的恐惧往往源自不了解,如果你能把它写出来,还怕不会用 吗?
对于那些对 C++标准库中的 string 不甚了解的读者来说,这篇文章的名称 可 能 会 引 起 一 些 混 淆 。 标 准 库 中 的 string 并 不 是 一 个 独 立 的 类 , 而 是 basic_string 模板类的一个特化版本: typedef basic_string<char, char_traits<char>, allocator<char> > string;
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&); //下标操作符
return p_str[in源自ex]; }//'+'操作符的重载 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; }
char& operator[] (const size_t); const char& operator[] (const size_t)const; //赋值操作符
MyString& operator=(const MyString&); //'+='操作符
MyString& operator+=(const MyString&);
有几个问题需要说明。 1、IO 操作符不可以定义为类的成员函数,否则,左操作数只能是该类类型的对 象。
MyString s; s<<cout;
这你能忍? 2、算术和关系操作符一般情况下应定义为非成员函数,它们并不会改变操作数 的状态。 3、上述操作符既为非成员函数,又要访问类的私有数据成员,所以将它们设为 类的友元。 4、下标操作符定义了两个,第二个是对应类对象是 const 的情况,否则,类的 const 对象将无法使用下标。 最后,再写一些操作函数。标准库 string 的操作函数为数众多,且存在大量的 重载版本。这里出于篇幅考虑,选择几个代表性的函数来实现。
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() {
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) {
const char* c_str();//返回 C 风格字符串的指针
下面该写操作符了,我们知道,string 支持的操作符特别多,这些都是通 过操作符的重载实现的。
//读写操作符
friend ostream& operator<< (ostream&,const MyString&); friend istream& operator>> (istream&,MyString&); //‘+’操作符
delete[] p_str; }
几个简单的成员函数
size_t MyString::length()
{ return strLength;
}
bool MyString::empty() {
return strLength==0?true:false; }
const char* MyString::c_str() {
至此,MyString 类的声明就告一段落了。
实现篇
类的声明虽然代码篇幅较短,但其是设计一个类的重中之重。声明做得很完 善,实现一般不会困难。下面依据上文声明的次序给出函数的实现。 构造函数和析构函数
MyString::MyString():strLength(0),p_str(NULL){}
MyString::MyString(const MyString& str) {
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) {
//'+='操作符 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; }
操作符的重载:
//输出操作符
ostream& operator<< (ostream& out,const MyString& str) {
if(str.p_str!=NULL) out<<str.p_str;
return out; }
//输入操作符 istream& operator>>(istream& in,MyString& str)// {
//赋值操作符 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; }