通过测试上述代码可正常运行,特别是在实现赋值运算符重载的时候我们使用了两种方式,值得一提的是应用swap函数来实现赋值运算符的重载(在传参时不可以传引用),因为应用swap函数实现是根据临时变量的创建并且该临时变量出作用域就会自动调用析构函数销毁(现代的方法)
测试深拷贝的方法
void text1()
{
String str1("hello");
String str2(str1);
String str3;
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
}
void text2()
{
String str1("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;
}
void text3()
{
String str1("hello");
String str2("hello world");
String str3(str2);
str1+=" ";
str1+="world";
cout<<str1<<endl;
str2.Insert(6," abc ");
cout<<str2<<endl;
}
实现了深拷贝的方法那仫有没有更加高效的方法呢?当然,那就是写时拷贝,我们发现在上述深拷贝的版本里实现的拷贝构造函数又为新的对象重新开辟空间(防止浅拷贝的后遗症:浅拷贝是值拷贝使得两个指针指向同一块空间,在析构该空间时对同一块空间释放多次就会出现问题),那仫如果我们继承了浅拷贝的后遗症-就让多个指针指向同一块空间,此时我们只需要设置一个指针变量让它记录指向这块空间的指针个数,在析构时只要该指针变量的内容为1我们就释放这块空间否则就让计数器减1,这就是写时拷贝的主要思想,下面就让我们用写时拷贝的方法实现一个简单的String类吧
写时拷贝的方法
//写时拷贝的方式
class String
{
friend ostream& operator<<(ostream & os,String &s);
public:
String(const char *str="")
:_str(new char[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=(const String &s)
{
cout<<"赋值语句"<<endl;
if(--*(int *)(_str-4) == 0)
{
delete[](_str-4);
}
++(*(int *)(s._str-4));
_str=s._str;
return *this;
}
char &operator[](int index) //写时拷贝
{
assert(index >= 0 && index < (int)strlen(_str));
if(*(int *)(_str-4) > 1)
{
--*(int *)(_str-4);
char *tmp=new char[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;
return os;
}










