string类和深浅拷贝
c++中将字符串以及操作它的函数单独分装了起来,成为string类,由string类引入深浅拷贝。
一个类中若没有定义拷贝构造函数,就会调用系统默认的拷贝构造函数,比如下面Time类中,没有定义拷贝构造函数
Time t1;
Time t2(t1); //拷贝t2 = t1;
t2 = t1; //赋值
//若没有在类中定义拷贝构造函数和赋值运算符函数,这两种情况都是使t1和t2共享同一块内存
深浅拷贝底层实现:
所以编译器默认的拷贝、赋值都是浅拷贝,浅拷贝时会出问题,若在类中定义拷贝构造函数,拷贝时实现的就是深拷贝,既复制了全部成员和数据,也开辟了新空间,析构时,析构自己的空间。
string类深拷贝的传统写法和现代写法(即拷贝构造函数和赋值运算符重载的实现)
拷贝构造函数和赋值运算符函数的传统写法
class String
{
public:
String(const char *pstr ) //构造函数
{
if (pstr = NULL)
{
pstr = "";
}
else
{
str = new char[strlen(pstr) + 1];
strcpy(str, pstr);
}
}
//拷贝构造函数的实现
String(const String&s)
:str(new char[strlen(s.str) + 1]) //申请新空间
{
strcpy(str, s.str);
}
//赋值运算符重载方法一
String& operator=(const String&s)
{
if (this != &s) //如果不是自己给自己复制
{
delete[] str; //则释放旧空间,因为新的字符可能在旧地之中放不下
str = new char[strlen(s.str) + 1]; //申请新空间
strcpy(str, s.str); //拷贝内容
}
}
/*赋值运算符重载方法二
String& operator=(const String&s)
{
if (this != &s) //如果不是自己给自己复制
{
char *pstr = new char[strlen(s.str) + 1]; //给定新空间
strcpy(pstr, s.str);
delete[] str;
str = pstr; //交换指向
}
}*/
~String() //析构函数
{
if (str)
delete[] str;
}
private:
char *str;
};
拷贝构造函数和赋值运算符函数的现代写法
class String
{
public:
String(const char *pstr) //构造函数
{
if (pstr = NULL)
{
pstr = "";
}
else
{
str = new char[strlen(pstr) + 1];
strcpy(str, pstr);
}
}
//拷贝构造函数的实现
String(const String &s)
:str(NULL) //给一个合法的指向
{
String strtmp(s.str);
swap(str, strtmp.str);
}
// 赋值运算符重载的三种方法
String &operator=(const String&s)
{
// 方法一
if (this != &s)
{
String strtmp(s.str);
swap(str, strtmp.str);
}
return *this;
//方法二
/*String strtmp(s);
swap(str, strtmp);
return *this;*/
}
//方法三
//String& operator=(String s)
//{
// swap(str, s.str);
// return *this;
//}
~String() //析构函数
{
if (str)
delete[] str;
}
private:
char *str;
};
void test()
{
String st1("hello");
String st2(st1);
st2 = "world";
String st3 = st2; //检测三个空间三个地址是否相同
}
现代方法实现``````对比两者种方法的区别对于拷贝构造函数来说,传统方法需要申请新空间,但现代版不需要,直接创建一个对象,因为对象一旦创建,数据的底层空间就开辟了出来,然后利用交换来实现;对于赋值运算符重载来说,传统版本重点在于释放旧空间,申请新空间,现代版本利用创建对象和交换函数来实现。