浅拷贝
1.浅拷贝是所有对象都共用一块空间,一个对象改变,所有对象都跟着改变,在调用析构函数的时候,也会发生错误,会释放已经释放的空间。
class String
{
public:
String(const char* pstr = "")//构造函数
{
if (pstr == NULL)//字符串为空
{
_pstr=new char[1];
*_pstr = '\0';
}
else//字符串不为空
{
_pstr = new char[strlen(pstr) + 1];
strcpy(_pstr,pstr);
}
}
String(const String &s)//拷贝构造
{
_pstr = s._pstr;
}
String& operator=(String& s)//赋值运算符的重载
{
if (_pstr != s._pstr)
{
_pstr = s._pstr;
}
return *this;
}
~String()
{
if (_pstr == NULL)
return;
else
{
delete[]_pstr;
_pstr = NULL;
}
}
private:
char* _pstr;
};
void Funtest()
{
String s1("abcd");
String s2(s1);
String s3 = s2;
String s4;
s4 = s3;
}
int main()
{
Funtest();
system("pause");
return 0;
}
四个对象共用一块空间,接下来是调用析构函数,首先调用s4的析构函数,接下来再继续调用析构函数就会发生错误。
对于以上的程序,我们可以想用计数的方式,每次构造一个对象就使计数器+1,在调用析构的时候使计数器-1,当计数器值为0的时候再去释放空间,代码如下:
class String
{
public:
String(const char* pstr = "")//构造函数
,_count(0)
{
if (pstr == NULL)//字符串为空
{
_pstr=new char[1];
*_pstr = '\0';
}
else//字符串不为空
{
_pstr=new char[strlen(pstr) + 1];
strcpy(_pstr, pstr);//将字符串的首地址复制过去
}
_count++;
}
String(String &s)//拷贝构造
{
_pstr = s._pstr;
_count = s._count;
_count++;
}
String& operator=(String& s)//赋值运算符的重载
{
if (_pstr != s._pstr)
{
_pstr = s._pstr;
_count = s._count;
_count++;
}
return *this;
}
~String()
{
if (_pstr == NULL)
return;
else
{
if (--_count == 0)
{
delete[]_pstr;
_pstr = NULL;
}
}
}
private:
char* _pstr;
int _count;
};
void Funtest()
{
String s1("abcd");
String s2(s1);
String s3 = s2;
String s4;
s4 = s3;
}
int main()
{
Funtest();
system("pause");
return 0;
}
当创建对象完成时,每个对象中保存的_count的值是不一样的,如下:
进而当进行析构时,并不能使每个对象中的 _count的值都为0
由此我们会想到,当一个类有多个对象时,这些对象中的静态成员数据共用一块存储空间,可以使用静态的成员数据来存储对象的个数,每个对象中的计数器中的数据保持一致。
class String
{
public:
String(const char* pstr = "")//构造函数
{
if (pstr == NULL)//字符串为空
{
_pstr=new char[1];
*_pstr = '\0';
}
else//字符串不为空
{
_pstr=new char[strlen(pstr) + 1];
strcpy(_pstr, pstr);//将字符串的首地址复制过去
}
_count++;
}
String(String &s)//拷贝构造
{
_pstr = s._pstr;
_count = s._count;
_count++;
}
String& operator=(String& s)//赋值运算符的重载
{
if (_pstr != s._pstr)
{
_pstr = s._pstr;
_count = s._count;
_count++;
}
return *this;
}
~String()
{
if (_pstr == NULL)
return;
else
{
if (--_count == 0)
{
delete[]_pstr;
_pstr = NULL;
}
}
}
private:
char* _pstr;
static int _count;
};
int String::_count = 0;
void Funtest()
{
String s1("abcd");
String s2(s1);
String s3 = s2;
String s4;
s4 = s3;
}
int main()
{
Funtest();
system("pause");
return 0;
}
但这样运行的结果也是不正确的,他会使_count的值为5,然而只调用4次析构函数,不能释放空间。
指针的形式:
class String
{
public:
String(const char* pstr = "")//构造函数
, _count(new int(0))
{
if (pstr == NULL)//字符串为空
{
_pstr=new char[1];
*_pstr = '\0';
}
else//字符串不为空
{
_pstr=new char[strlen(pstr) + 1];
strcpy(_pstr, pstr);//将字符串的首地址复制过去
}
*_count=1;
}
String(String &s)//拷贝构造
{
_pstr = s._pstr;
_count = s._count;
(*_count)++;
cout << "String(String &s)" << endl;
}
String& operator=(String& s)//赋值运算符的重载
{
if (_pstr != s._pstr)
{
_pstr = s._pstr;
_count = s._count;
(*_count)++;
}
return *this;
}
~String()
{
if (_pstr == NULL)
return;
else
{
if (--(*_count) == 0)
{
delete[]_pstr;
delete _count;
_pstr = NULL;
_count = NULL;
}
}
}
private:
char* _pstr;
int* _count;
};
深拷贝
深拷贝中每个对象并不占用同一块空间,而是各自有各自的空间,这样就不会互相影响而产生不必要的结果。
深拷贝普通版
class String
{
public:
String(const char* pstr = "")
:_pstr(new char[strlen(pstr)+1])
{
if (pstr == NULL)
{
*_pstr = '\0';
}
else
{
strcpy(_pstr,pstr);
}
}
String(const String &s)
:_pstr(new char[strlen(s._pstr) + 1])
{
strcpy(_pstr,s._pstr);
}
String& operator=(const String& s)
{
if (_pstr != s._pstr)
{
char* tmp = new char[strlen(s._pstr) + 1];
tmp= s._pstr;
delete[]_pstr;
_pstr=tmp;
}
return *this;
}
~String()
{
if (_pstr == NULL)
{
return;
}
else
{
delete[] _pstr;
_pstr = NULL;
}
}
private:
char* _pstr;
};
深拷贝简洁版
class String
{
public:
String(const char* pstr = "")
{
if (pstr == NULL)
{
_pstr = new char[1];
*_pstr = '\0';
}
else
{
_pstr=new char[strlen(pstr) + 1];
strcpy(_pstr, pstr);
}
}
String(const String &s)
:_pstr(new char[strlen(s._pstr) + 1])
{
strcpy(_pstr, s._pstr);
}
/* String(String &s)
:_pstr(NULL)
{
String tmp(s._pstr);
swap(_pstr,s._pstr);
}*/
//赋值运算符重载第一种方式
String& operator=(String s)//不用对象的引用,不会占用同一块空间
{
//不用if判断
swap(_pstr,s._pstr);
return *this;
}
//赋值运算符重载第二种方式
/*String& operator=(const String& s)//已经定义了拷贝构造函数
{
if (_pstr != s._pstr)
{
String tmp(s);//调用拷贝构造函数
swap(_pstr,tmp._pstr);
}
return *this;
}*/
//赋值运算符重载第三种方式
String& operator=(const String& s)//没有定义拷贝构造函数时
{
if (_pstr != s._pstr)
{
String tmp(s._pstr);//只能调用构造函数
swap(_pstr, tmp._pstr);
}
return *this;
}
~String()
{
if (_pstr == NULL)
{
return;
}
else
{
delete[] _pstr;
_pstr = NULL;
}
}
private:
char* _pstr;
};
void Funtest()
{
String s1("abcd");
String s2(s1);
String s3 = s2;
String s4;
s4 = s3;
}
int main()
{
Funtest();
system("pause");
return 0;
}