在C++ 中,当类对象之间相互赋值的时候会存在拷贝的问题。特别是在使用vector对类对象进行管理的时候,这个问题会比较明显。这个时候,定义类的拷贝构造函数就很有作用了。
先说说浅拷贝的情况,代码如下:
#include <iostream>
using namespace std;
class image
{
public:
int *pImgdata;
int width;
int height;
image(int w, int h);
~image();
};
image::image(int w, int h)
{
width = w;
height = h;
pImgdata = new int[w * h];
}
image::~image()
{
}
void main()
{
image A(100, 100);
cout << "A的地址是: " <<A.pImgdata << endl;
image B = A;
cout << "B的参数时: " << endl;
cout << B.height << endl;
cout << B.width << endl;
cout << B.pImgdata << endl;
delete[] B.pImgdata;
delete[] A.pImgdata;
cin.get();
}
运行结果如下:
从运行结果可以看出,
当将对象A赋值给对象B的时候,采用的是直接赋值的方法,对象A的width和height参数成功赋值给对象B,同时对象B和A的指针的地址相同,地址也成功复制了。但是后面出错了,问题在于,对象A虽然将指针地址成功赋值给B,但是A与B的指针指向的是同一块新建的内存,即对象A的指针的那块内存。所以,程序中,执行语句
delete[ ] B.pImgdata;
的时候,表面上看是释放的对象B 的内存,实际释放的是对象A的内存,因为在对象的赋值过程中,并没有给对象B新开辟内存,仅仅是将A的指针地址赋值给了对象B,这样对象B与A的指针实际都指向的是A的指针所指向的那块内存。所以,当程序在执行语句:
delete[] A.pImgdata;
的时候,就相当于对同一块内存进行了二次释放。但是,用new开辟的内存,只能用delete释放一次,如果多次释放同一块new的内存则会出错。这就是程序问题的所在。
这就是浅拷贝的情况,只是对对象中的相关参数的值进行了拷贝和复制,但是对相关更深入的,比如内存啥的,并没有复制。
下面就上面出现的问题,结合类的拷贝构造函数说下深拷贝的情况。
在上述的代码上为类添加了类的拷贝构造函数。主函数不变,修改后的类声明和拷贝构造函数的定义如下:
class image
{
public:
int *pImgdata;
int width;
int height;
image(int w, int h);
image(const image& C);
~image();
};
拷贝构造函数:
image::image(const image& C)
{
width = C.width;
height = C.height;
pImgdata = new int[width * height];
}
在拷贝构造函数中,新开辟了内存。运行结果如下:
结果看出,对象A与B的指针的地址不同,最后两句释放内存的语句都能顺利运行,说明对象A与B的指针都有各自不用的内存块,所以才能两次分别释放内存。
关于拷贝构造函数的声明、定义和相关注意的格式问题:
拷贝构造函数是一种特殊的构造函数,函数没有返回值,函数名称和类名称一致,其唯一的一个参数必须是本类类型的一个引用变量,必须是引用类型,而且还是本类型的类对象,必须是const常量类型。比如本例程中的构造函数如下:
image(const image& C); //声明形式
//函数定义如下
image::image(const image& C)
{
width = C.width;
height = C.height;
pImgdata = new int[width * height];
}
和一般的构造函数声明形式和定义差不多。