C++中sting类的简单实现方法
String
在C++的学习生涯我中发现String类的功能十分强大,所以我们是很有必要模拟实现它的,况且在面试的时候模拟实现一个String类也是面试官经常会考的,但是因为外界因素的限制我们是不可能模拟的和库里的string一致的(C++库里的string功能更强大),所以今天我们只模拟实现string的基本功能-构造函数,拷贝构造函数,析构函数,赋值运算符重载,运算符+=的重载,运算符[]的重载,c_str(得到一个C风格的字符指针,可操作字符串),Size,Push_Back,Insert(深拷贝),以及用写时拷贝copy_on_write的方式实现基本的String类
深拷贝的方式
classString
{
friendostream&operator<<(ostream&os,String&s);
public:
String(constchar*str="");//全缺省的构造函数,解决空字符串的问题
String(constString&ps);//深拷贝
String&operator=(Strings);
String&operator+=(constchar*s);
constchar*C_Str()const//得到C风格的字符指针
{
return_pstr;
}
char&operator[](size_tindex)
{
return_pstr[index];
}
size_tSize()const
{
return_size;
}
voidPushBack(charc);
String&Insert(size_tpos,constchar*str);
//String&operator=(String&s)
//{
//cout<<"String&operator=(String&s)"<<endl;
//if(this!=&s)
//{
//delete[]_pstr;
//_pstr=newchar[strlen(s._pstr)+1];
//strcpy(_pstr,s._pstr);
//}
//return*this;
//}
~String()
{
cout<<"~String()"<<endl;
if(_pstr!=NULL)
{
delete[]_pstr;
_pstr=NULL;
_size=0;
_capacity=0;
}
}
private:
voidCheckCapacity(intcount);
private:
int_size;
int_capacity;
char*_pstr;
};
ostream&operator<<(ostream&os,String&s)
{
os<<s._pstr;
returnos;
}
String::String(constchar*str)
:_size(strlen(str))
,_capacity(strlen(str)+1)
,_pstr(newchar[_capacity])
{
cout<<"String()"<<endl;
strcpy(_pstr,str);
}
String::String(constString&ps)
:_size(ps._size)
,_capacity(strlen(ps._pstr)+1)
,_pstr(newchar[_capacity])
{
cout<<"String(constString&ps)"<<endl;
strcpy(_pstr,ps._pstr);
}
String&String::operator=(Strings)
{
cout<<"String&operator=(Strings)"<<endl;
std::swap(_pstr,s._pstr);
std::swap(_size,s._size);
std::swap(_capacity,s._capacity);
return*this;
}
voidString::CheckCapacity(intcount)
{
if(_size+count>=_capacity)
{
int_count=(2*_capacity)>(_capacity+count)?(2*_capacity):(_capacity+count);
char*tmp=newchar[_count];
strcpy(tmp,_pstr);
delete[]_pstr;
_pstr=tmp;
_capacity=_count;
}
}
voidString::PushBack(charc)
{
CheckCapacity(1);
_pstr[_size++]=c;
_pstr[_size]='\0';
}
String&String::operator+=(constchar*s)
{
CheckCapacity(strlen(s));
while(*s)
{
_pstr[_size++]=*s;
s++;
}
_pstr[_size]='\0';
return*this;
}
String&String::Insert(size_tpos,constchar*str)
{
char*tmp=newchar[strlen(_pstr+pos)];
strcpy(tmp,_pstr+pos);
CheckCapacity(strlen(str));
while(*str)
{
_pstr[pos++]=*str;
str++;
}
strcpy(_pstr+pos,tmp);
return*this;
}
通过测试上述代码可正常运行,特别是在实现赋值运算符重载的时候我们使用了两种方式,值得一提的是应用swap函数来实现赋值运算符的重载(在传参时不可以传引用),因为应用swap函数实现是根据临时变量的创建并且该临时变量出作用域就会自动调用析构函数销毁(现代的方法)
测试深拷贝的方法
voidtext1()
{
Stringstr1("hello");
Stringstr2(str1);
Stringstr3;
str3=str1;
cout<<str1<<endl;
cout<<str2<<endl;
cout<<str3<<endl;
cout<<strlen(str1.C_Str())<<endl;//5
str1[4]='w';
cout<<str1<<endl;//hellw
}
voidtext2()
{
Stringstr1("abcd");
cout<<str1<<endl;
str1.PushBack('e');
str1.PushBack('f');
str1.PushBack('g');
str1.PushBack('h');
str1.PushBack('i');
cout<<str1<<endl;
cout<<str1.Size()<<endl;
}
voidtext3()
{
Stringstr1("hello");
Stringstr2("helloworld");
Stringstr3(str2);
str1+="";
str1+="world";
cout<<str1<<endl;
str2.Insert(6,"abc");
cout<<str2<<endl;
}
实现了深拷贝的方法那仫有没有更加高效的方法呢?当然,那就是写时拷贝,我们发现在上述深拷贝的版本里实现的拷贝构造函数又为新的对象重新开辟空间(防止浅拷贝的后遗症:浅拷贝是值拷贝使得两个指针指向同一块空间,在析构该空间时对同一块空间释放多次就会出现问题),那仫如果我们继承了浅拷贝的后遗症-就让多个指针指向同一块空间,此时我们只需要设置一个指针变量让它记录指向这块空间的指针个数,在析构时只要该指针变量的内容为1我们就释放这块空间否则就让计数器减1,这就是写时拷贝的主要思想,下面就让我们用写时拷贝的方法实现一个简单的String类吧
写时拷贝的方法
//写时拷贝的方式
classString
{
friendostream&operator<<(ostream&os,String&s);
public:
String(constchar*str="")
:_str(newchar[strlen(str)+1+4])
{
cout<<"构造"<<endl;
_str+=4;
*((int*)(_str-4))=1;
strcpy(_str,str);
}
String(String&s)
{
cout<<"拷贝构造"<<endl;
++*((int*)(s._str-4));
_str=s._str;
}
String&operator=(constString&s)
{
cout<<"赋值语句"<<endl;
if(--*(int*)(_str-4)==0)
{
delete[](_str-4);
}
++(*(int*)(s._str-4));
_str=s._str;
return*this;
}
char&operator[](intindex)//写时拷贝
{
assert(index>=0&&index<(int)strlen(_str));
if(*(int*)(_str-4)>1)
{
--*(int*)(_str-4);
char*tmp=newchar[strlen(_str)+5];
strcpy(tmp+4,_str);
delete[](_str-4);
_str=tmp+4;
*(int*)(_str-4)=1;
}
return_str[index];
}
~String()
{
cout<<"析构"<<endl;
if(--*(int*)(_str-4)==0)
{
cout<<"释放"<<endl;
delete[](_str-4);
}
}
private:
char*_str;
};
ostream&operator<<(ostream&os,String&s)
{
os<<s._str;
returnos;
}
在这里我们将指针指向的计数器的位置放置在数据空间的前四个字节处
测试用例:
voidtest1()
{
Stringstr1("abcd");
cout<<str1<<endl;
Stringstr2(str1);
cout<<str2<<endl;
Stringstr3;
str3=str1;
cout<<str3<<endl;
}
voidtest2()
{
Stringstr1("abcd");
cout<<str1<<endl;
Stringstr2;
str2=str1;
cout<<str2<<endl;
str2[2]='w';
cout<<str2<<endl;
}
以上所述是小编给大家介绍的C++中sting类的简单实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!