一、概念字面理解
1、浅拷贝:发生对象复制时,只是对对像张数据成员进行简单的赋值。涉及到动态分配问题,如果按浅拷贝进行复制,不做特殊处理,复制完成后,两个对象中涉及动态分配空间的变量,不管他们各自的空间,及空间中的内容都是完全一样的,当对这两个对象进行析构时,会发生同一片空间被释放两次,因而会出现错误。
如指针,浅拷贝只是对指针进行复制,复制完成后,两个指针指向同一个内存空间,而深拷贝不止对指针进行复制,也对指针指向的内容进行复制,深拷贝后,两个指针指向不同地址的内存空间,但内容相同。
浅拷贝可能存在的问题(均是指存在动态分配或者指针变量的情况下):
(1)析构时,同一个内存空间可能会被释放两次,这是错误的;
(2)经浅拷贝后,指向同一个内存空间,任何一方变动都会影响到另一方;
(3)假如类存在char *ch,class_name obj1(obj),因为obj.ch和obj1.ch指向同一个内存空间,当delete obj.ch,delete.obj.ch内存被释放后,obj1.ch所指的空间不能在被利用了,delete.obj1.ch也不会成功,也会导致一直无法操作该空间,因而会导致内存泄漏。结论:在释放时,会因为obj1.ch的内存没有被释放,造成内存泄漏。
eg:
- class Rect
- {
- public:
- Rect() // 构造函数,p指向堆中分配的一空间
- {
- p = new int(100);
- }
- ~Rect() // 析构函数,释放动态分配的空间
- {
- if(p != NULL)
- {
- delete p;
- }
- }
- private:
- int width;
- int height;
- int *p; // 一指针成员
- };
- int main()
- {
- Rect rect1;
- Rect rect2(rect1); // 复制对象
- return 0;
- }
说明:类Rect中有动态分配存在;
rect1复制给rect2,在Line23会隐式调用默认拷贝构造函数,浅拷贝,只是对象数据成员的赋值操作,此时,rect1.p和rect2.p不仅值相同,而且指向同一片空间,因此在程序执行完成前,及在进行析构时会发生错误:同一片地址空间被释放两次;
改进方法是采用深拷贝:
eg:
- class Rect
- {
- public:
- Rect() // 构造函数,p指向堆中分配的一空间
- {
- p = new int(100);
- }
- Rect(const Rect& r)
- {
- width = r.width;
- height = r.height;
- p = new int; // 为新对象重新动态分配空间
- *p = *(r.p);
- }
- ~Rect() // 析构函数,释放动态分配的空间
- {
- if(p != NULL)
- {
- delete p;
- }
- }
- private:
- int width;
- int height;
- int *p; // 一指针成员
- };
2、深拷贝
3、对象复制
4、对象的赋值
5、默认拷贝构造函数、自定义拷贝构造函数
其他:
(1)声明一个私有的拷贝构造函数,可以防止默认拷贝发生。如果试图调用 A b(a); 就调用了私有的拷贝构造函数,编译器会报错。
(2)一个类中可以存在多个拷贝构造函数。(const拷贝和非const拷贝)
eg:
- Calss A
- {
- Public:
- X(const X&);//const拷贝构造
- X(X &);//非const拷贝构造
- X(X& , int iData);
- }