c语言中文网
http://m.biancheng.net/view/2336.html
其实发现这些基础面试题确实很基础 但是以前都没有去注意)
定义
如普通的赋值,没有指针和内存分配的类对象互相赋值是以拷贝的方式初始化对象,按照默认的二进制位方式进行拷贝,这种默认的拷贝方式就是浅拷贝,这和调用 memcpy() 函数的效果非常类似。
对于简单的类,默认的拷贝构造函数一般就够用了,我们也没有必要再显式地定义一个功能类似的拷贝构造函数。但是当类持有其它资源时,例如动态分配的内存、指向其他数据的指针等,默认的拷贝构造函数就不能拷贝这些资源了,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据。
#include <iostream>
#include <cstdlib>
using namespace std;
//变长数组类
class Array{
public:
Array(int len);
Array(const Array &arr); //拷贝构造函数
~Array();
public:
int operator[](int i) const { return m_p[i]; } //获取元素(读取)
int &operator[](int i){ return m_p[i]; } //获取元素(写入)
int length() const { return m_len; }
private:
int m_len;
int *m_p;
};
Array::Array(int len): m_len(len){
m_p = (int*)calloc( len, sizeof(int) );
}
Array::Array(const Array &arr){ //拷贝构造函数
this->m_len = arr.m_len;
this->m_p = (int*)calloc( this->m_len, sizeof(int) );
memcpy( this->m_p, arr.m_p, m_len * sizeof(int) );
}
Array::~Array(){ free(m_p); }
//打印数组元素
void printArray(const Array &arr){
int len = arr.length();
for(int i=0; i<len; i++){
if(i == len-1){
cout<<arr[i]<<endl;
}else{
cout<<arr[i]<<", ";
}
}
}
int main(){
Array arr1(10);
for(int i=0; i<10; i++){
arr1[i] = i;
}
Array arr2 = arr1;
arr2[5] = 100;
arr2[3] = 29;
printArray(arr1);
printArray(arr2);
return 0;
}
我们显式地定义了拷贝构造函数,它除了会将原有对象的所有成员变量拷贝给新对象,还会为新对象再分配一块内存,并将原有对象所持有的内存也拷贝过来。这样做的结果是,原有对象和新对象所持有的动态内存是相互独立的,更改一个对象的数据不会影响另外一个对象
这种将对象所持有的其它资源一并拷贝的行为叫做深拷贝,我们必须显式地定义拷贝构造函数才能达到深拷贝的目的。
深拷贝的例子比比皆是,除了上面的变长数组类,动态数组类也需要深拷贝;此外,标准模板库(STL)中的 string、vector、stack、set、map 等也都必须使用深拷贝。
何时使用深拷贝或者浅拷贝
如果一个类拥有指针类型的成员变量,那么绝大部分情况下就需要深拷贝,因为只有这样,才能将指针指向的内容再复制出一份来,让原有对象和新生对象相互独立,彼此之间不受影响。
如果类的成员变量没有指针,一般浅拷贝足以。