浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。
存在问题:
如果源程序中没有显示定义拷贝构造函数,在进行对象的拷贝时,将调用系统默认的拷贝构造函数,这就使得两个对象指向了同一资源,而析构函数又在对象生命周期结束后可以释放空间,势必会两次返还空间,编译器就会报错。
这时就需要用到深拷贝了。
深拷贝的两种版本:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//#if 0
class String
{
public:
String(char *pStr = "") //构造函数
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = 0;
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
//简洁版
拷贝构造函数 1
//String(const String &s)
// :_pStr(new char[strlen(s._pStr) + 1])
//{
// String temp(s._pStr);
// swap(_pStr, temp._pStr);
//}
拷贝构造函数 2
//String(const String &s)
// :_pStr(NULL)
//{
// _pStr = new char[1];
// String temp(s._pStr);
// swap(_pStr, temp._pStr);
//}
//普通版
String(const String &s)
:_pStr(new char[strlen(s._pStr) + 1])
{
strcpy(_pStr, s._pStr);
}
//赋值运算符重载
/*
//由于pTemp在栈上,出了函数将销毁,故错误
String &operator=(const String &s)//赋值运算符重载
{
if (this != &s)
{
char *pTemp = new char[strlen(s._pStr) + 1];// pTemp在栈上
strcpy_s(pTemp, strlen(s._pStr), s._pStr);
//strcpy_s(_pStr, strlen(pStr), pStr);
delete[] _pStr;
_pStr = pTemp;
}
return *this;
}
*/
//赋值运算符重载 1
/*
String &operator=(const String &s)
{
//if (this != &s) 赋值运算符重载的反例,会造成一块空间多次释放
//{
// _pStr = s._pStr;
//}
//return *this;
if (this != &s)
{
String temp(s._pStr);//用S里面的字符串构造一个临时的temp
swap(_pStr, temp._pStr);//交换两个指针
}
return *this;
}
*/
//赋值运算符重载 2
String& operator=(const String& pStr)
{
if (this != &pStr)
{
//防止new开辟内存失败,丢失原来内存
char* ptr = new char[strlen(pStr._pStr) + 1];
strcpy(ptr, pStr._pStr);
delete[]_pStr;
_pStr = ptr;
}
return *this;
}
~String() //析构函数
{
if (this != NULL)
{
delete[] _pStr;
_pStr = NULL;//可有可无
}
}
friend ostream& operator<<(ostream & _cout, const String&pStr);
private:
char *_pStr;
};
//输出流重载
ostream& operator<<(ostream & _cout, const String&pStr)
{
_cout << pStr._pStr << endl;
return _cout;
}
void FunTest1()
{
String s1("hello");
cout << "s1=" << s1 << endl;
String s2(s1); //调用拷贝构造函数
cout << "s2=" << s2 << endl;
}
void FunTest2()
{
String s3("word");
String s4;
s4 = s3; //调用赋值运算符重载
cout << "s3=" << s3 << endl;
cout << "s4=" << s4 << endl;
}
int main()
{
FunTest1();
FunTest2();
getchar();
return 0;
}
//#endif
1、开辟两个空间的计数,代码如下:
#include<iostream>
using namespace std;
class String
{
public:
String(const char * pStr = "")//构造函数
:_pCount(new int(1)) //_pCount初始化为1
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
String(const String &s)//拷贝构造函数
:_pStr(s._pStr)
, _pCount(s._pCount)
{
++*_pCount;//调用一次拷贝构造函数_pCount++
}
//赋值运算符重载
String & operator = (const String & s)
{
if (this != &s)
{
if (0 == --*_pCount)
{
delete[] _pStr;
delete _pCount;
}
_pStr = s._pStr;
_pCount = s._pCount;
++*_pCount;
}
}
~String()//调用析构函数时 先--_pCount,判断是否为0
{
if ((_pStr) && (0 == --*_pCount))
{
delete[] _pStr;
_pStr = NULL;
delete _pCount;
_pCount = NULL;
}
}
friend ostream& operator<<(ostream & output, const String &s);
private:
char * _pStr;
int * _pCount;
};
ostream& operator<<(ostream & output, const String &s)//输出流的重载
{
output << s._pStr << endl;
return output;
}
void FunTest()
{
String s1("hello");
cout << "s1=" << s1 << endl;
String s2(s1);
cout << "s2=" << s2 << endl;
String s3("heihei");
cout << "s3=" << s3 << endl;
String s4 = s3;
cout << "s4=" << s4 << endl;
}
int main()
{
FunTest();
getchar();
return 0;
}
运行结果:
2、一个空间的计数,代码如下:
class String
//{
//public:
// String(char* ptr = NULL)
// {
// if (ptr == NULL)
// {
// _ptr = new char[5];
// *(_ptr + 4) = 0;
// }
// else
// {
// _ptr = new char[strlen(ptr) + 5];
// strcpy(_ptr + 4, ptr);
// }
// *(int*)_ptr = 1;
// }
// String(const String& s)
// :_ptr(s._ptr)
// {
// (*(int*)_ptr)++;
// }
// String& operator=(const String& s)
// {
// if (&s != this)
// {
// _ptr = s._ptr;
// (*(int*)_ptr)++;
// }
// return *this;
// }
// ~String()
// {
// if (--*(int*)_ptr == 0)
// {
// delete[] _ptr;
// _ptr = NULL;
// }
// }
//private:
// char* _ptr;
//};
class String
{
public:
String(const char* pStr)
{
if (pStr == NULL)
pStr = " ";
_pStr = new char[strlen(pStr) + 1 + 4];//多开辟4个字节
_pStr += 4;
strcpy(_pStr, pStr);
GetReference() = 1;
}
String(const String&s)
:_pStr(s._pStr)
{
++ GetReference();
}
String & operator = (const String & s)
{
if (this != &s)
{
if (--GetReference() = 0)
{
_pStr -= 4;
delete[] _pStr;
}
_pStr = s._pStr;
++GetReference();
}
}
~String()
{
if ((--GetReference() == 0) && _pStr)
{
_pStr -= 4;
delete[] _pStr;
_pStr = NULL;
}
}
friend ostream & operator<<(ostream &output, String &s);
private:
int& GetReference()
{
return *(int*)(_pStr - 4);
}
char* _pStr;
};
ostream & operator<<(ostream &output, String &s)
{
output << s._pStr << endl;
return output;
}
void FunTest()
{
String s1("ximenchuixue");
cout << "s1=" << s1 << endl;
String s2(s1);
cout << "s2=" << s2 << endl;
String s3("sikongzhaixing");
cout << "s3=" << s3 << endl;
String s4 = s3;
cout << "s4=" << s4 << endl;
}
int main()
{
FunTest();
getchar();
return 0;
}
运行结果: