什么是对象拷贝?
对象 | 对象 | 对象 | |||
---|---|---|---|---|---|
数组A | Object1 | Object2 | Object3 | ||
数组B | Object1 | Object2 | Object3 | Object4 | ...... |
例如:
随着工程发生变化,长度为3的数组A可能不够用了。
此时需要一个更大的数组来存放更多的内容,但是需要把原来的数据复制到新的更大的数组中。
如果是C语言,通常使用函数进行内存拷贝,那么在C++中也是做一样的工作,只不过在C++中它有自己的名称。
C++允许我们使用更简单的方法来进行内存的复制,这就是对象拷贝。
在C++中如何实现对象拷贝?
class MyObject
{
private:
int x;
int y;
public:
MyObject() { }
MyObject(int x, int y)
{
this->x = x;
this->y = y;
}
};
拷贝构造函数的调用
#include <iostream>
class MyObject
{
private:
int x;
int y;
public:
MyObject() { }
MyObject(int x, int y)
{
this->x = x;
this->y = y;
}
};
int main()
{
MyObject obj(1, 2);
//虽然没有定义传入对象类型的构造函数
//但是编译器会自动替我们提供该构造函数
//该构造函数拥有自己的名字:拷贝构造函数
//它的本质就是内存复制,只不过不需要我们去做,编译器已经替我们做了
MyObject objNew(obj);
//或者这样
MyObject* p = new MyObject(obj);
return 0;
}
注意:
由于编译器提供的拷贝构造函数只原封不动的复制对象成员的值,并不复制指针成员指向的内存里面的数据。
当对象成员中含有指针时,最好不要使用,而是自己实现一个拷贝构造函数,以免被拷贝的对象销毁后指针失效。
编译器提供的拷贝构造函数我们可以称为浅拷贝。
当能拷贝对象中成员的值且将指针成员指向的内存复制并申请新的内存去存放,我们可以称为深拷贝。
自己实现拷贝构造函数
#include <iostream>
class MyObject
{
private:
int Length;
char* Buffer;
public:
MyObject() { }
MyObject(const char* str)
{
Length = strlen(str) + 1;
Buffer = new char[Length];
//初始化缓冲区
memset(Buffer, 0, Length);
//复制
strcpy(Buffer, str);
}
//自定义拷贝构造函数、深拷贝
MyObject(const MyObject& obj)
{
Length = obj.Length;
Buffer = new char[Length];
//初始化缓冲区
memset(Buffer, 0, Length);
//复制
strcpy(Buffer, obj.Buffer);
}
~MyObject()
{
delete [] Buffer;
}
};
int main()
{
MyObject obj("Hello World");
MyObject objNew(obj);
return 0;
}
注意:
自定义拷贝构造函数参数一定需要是当前对象引用类型,如果修改为其他类型,不会进行真正的拷贝,哪怕修改为指针类型。
总结
- 如果不需要深拷贝,就不要添加拷贝构造函数。
- 如果添加了拷贝构造函数,那么编译器将不会提供,所有的事情都需要自己的拷贝构造函数完成。
- 如果当前类没有父类,则按上面的例子来使用即可。如果拥有父类,那么需要调用父类的拷贝构造函数,如下:
class Base
{
...
}
class MyObject:public Base
{
public:
MyObject (const MyObject& obj):Base(obj)
{
printf("拷贝构造函数\n");
}
};
MyObject (const MyObject& obj):Base(obj)