以拷贝的方式初始化对象
初始化对象时会调用构造函数,不同的初始化方式会调用不同的构造函数:
- 如果用传递进来的实参初始化对象,那么会调用普通的构造函数,我们不妨将此称为普通初始化;
- 如果用其它对象(现有对象)的数据来初始化对象,那么会调用拷贝构造函数,这就是以拷贝的方式初始化。
对于简单的类,默认的拷贝构造函数一般就够用了,我们也没有必要再显式地定义一个功能类似的拷贝构造函数。但是当类持有其它资源时,例如动态分配的内存、指向其他数据的指针等,默认的拷贝构造函数就不能拷贝这些资源了,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据。
这种将对象所持有的其它资源一并拷贝的行为叫做深拷贝,我们必须显式地定义拷贝构造函数才能达到深拷贝的目的。
重载=运算符
Array &Array::operator=(const Array &arr){ //重载赋值运算符 if( this != &arr){ //判断是否是给自己赋值 this->m_len = arr.m_len; free(this->m_p); //释放原来的内存 this->m_p = (int*)calloc( this->m_len, sizeof(int) ); memcpy( this->m_p, arr.m_p, m_len * sizeof(int) ); } return *this; }
关于为什么要返回*this:
解释如下:
为了编程的简洁性,有时候需要串联赋值,如:x = y = z = 15; 由于赋值采用右结合,因此上述语句被解释为:x = (y = (z = 15));
为了实现串联赋值,复制操作符函数必须返回一个指向操作符左侧实参的的引用,如下:
1 class Widget 2 { 3 public: 4 ... 5 Widget& operator=(const Widget& rhs) 6 { 7 ... 8 return *this; 9 } 10 ... 11 };
注意:
这个规则不仅适用于赋值 = ,对于其他操作符如 += 、 -= 等同样适用。
当定义一个类时,我们显式地或隐式地指定了此类型的对象在拷贝、赋值和销毁时做什么。一个类通过定义三种特殊的成员函数来控制这些操作,分别是拷贝构造函数、赋值运算符和析构函数。