拷贝构造函数
注意点
1.类声明只描述如何分配内存,并不会分配内存。因此,不要在类声明中初始化静态成员变量。 特殊情况:静态成员是const或者是枚举型时,则应在类声明中初始化。
2.会用到复制构造函数的声明:
point a(b);
point a = b;
point a = point b;
point *a = new point(b)
中间两个声明是等价的。并且有两种可能性,一种直接使用拷贝构造函数创建对象,一种使用拷贝构造函数创建一个临时变量,再调用重载的赋值运算符。
3.按值传递和返回对象也将调用拷贝构造函数。
4.由于第三点原因,我们在写函数参数时,应该使用引用传递对象,可以节省使用拷贝构造函数的时间和创建新对象的空间。
5.在类对象创建时,要避免浅复制(即使用了默认拷贝构造函数),两个对象指向同一段空间,遇到析构函数时,将会发生同一段空间被释放两次的情况,将会引发报错。
6.当我们看到类中的数据成员有指针变量或者静态数据成员时,需要主动提供一个显式拷贝构造函数
常见格式(深复制)
StringBad::StringBad(const StringBad &st)
{
num_string++; // 修改静态成员变量,符合我们第6个注意点
len = st.len; // 长度
str = new char[len + 1]; // 分配了一段空间,加1的目的是预留给\0(字符串结束符)空间
strcpy(str, st.str); // 把字符串复制到分配的空间中
}
赋值运算符重载
注意点
1.将一个已有对象赋值给一个对象时,将会使用重载的赋值运算符,在除初始化时,大部分两个对象都有值了。
2.赋值运算符不会产生新对象,因此不会对静态成员变量产生影响。有人可能会产生疑惑,在初始化时,我们也要用到重载的赋值运算符,那么势必需要修改静态成员变量。其实,初始化,有两种情况,之前已经说明了,细心的小伙伴已经发现了共同点,没错,初始化一定会使用拷贝构造函数,此时已经修改了静态成员变量,不用再担心了。
3.在重载赋值运算符时,要避免将对象赋值给自身。
常见格式
StringBad& StringBad::operator(const StringBad &st)
{
if(this == &st) // 首先检查自我复制
{
return *this
}
delete[] str // 释放可能有的旧的内容,防止之后产生内存泄漏
len = st.len // 长度
str = new char[len + 1] // 分配一段新空间
strcpy(str, st.str) // 把字符串复制到分配的空间中,此时若刚刚不delete空间,则会产生内存泄漏!
}