[TOC]

概述

文章参考:http://c.biancheng.net/view/2336.html

对于基本类型的数据以及简单的对象,它们之间的拷贝非常简单,就是按位复制内存。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Base{
public:
Base(): m_a(0), m_b(0){ }
Base(int a, int b): m_a(a), m_b(b){ }
private:
int m_a;
int m_b;
};
int main(){
int a = 10;
int b = a; //拷贝
Base obj1(10, 20);
Base obj2 = obj1; //拷贝
return 0;
}

b 和 obj2 都是以拷贝的方式初始化的,具体来说,就是将 a 和 obj1 所在内存中的数据按照二进制位(Bit)复制到 b 和 obj2 所在的内存,这种默认的拷贝行为就是浅拷贝,这和调用 memcpy() 函数的效果非常类似。

对于简单的类,默认的拷贝构造函数一般就够用了,我们也没有必要再显式地定义一个功能类似的拷贝构造函数。但是当类持有其它资源时,例如动态分配的内存、指向其他数据的指针等,默认的拷贝构造函数就不能拷贝这些资源了,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据。

下面我们通过一个具体的例子来说明显式定义拷贝构造函数的必要性。我们知道,有些较老的编译器不支持变长数组,例如 VC6.0、VS2010 等,这有时候会给编程带来不便,下面我们通过自定义的 Array 类来实现变长数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#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;
}