前言:
最近在做C++二级题的时候总是会遇到深拷贝,想想最先接触这个词的时候是在大话设计模式中,但是C++中的深拷贝和C#中的略有区别,今天先来介绍一下C++中的深拷贝吧!
简单的说:深拷贝的时候,相同数据指针指向不同的内存地址
浅拷贝的时候,指针指向相同的内存地址
现在来深入探讨一下:
浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间,浅拷贝只是对对象的简单拷贝,让几个对象共用一片内存,当内存销毁的时候,指向这片内存的几个指针需要重新定义才可以使用,要不然会成为野指针。
<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <iostream> #include <cstring> using namespace std; class Test { private: int a; char *str; public: Test(int b, char *s) { a=b; strcpy(str,s); //肇事地点,但不是祸端 } Test(const Test& C) { a=C.a; strcpy(str,C.str); } void show () { cout<<a<<","<<str<<endl; } }; int main() { Test a(100,"hello"); Test b(a); a.show(); b.show(); return 0; }</span>
那么如何解决这个问题呢?
就是在构造函数中,要为指针类型的成员,分配专门的空间。以这条规则构建的复制,称作为深复制!深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。
把上面的程序中改写一下完成深复制
<span style="font-family:KaiTi_GB2312;font-size:18px;">#include<iostream> using namespace std; class A { private: int *arrayAddr;//保存一个有len个整型元素的数组的首地址 int len; //记录动态数组的长度 public: A(int *a, int n); ~A(); int sum(); }; A::A(int *a, int n) { len=n; arrayAddr=new int[n]; //为指针数据成员分配空间,注意,没有上面例子中加1那回事 for(int i=0; i<n; i++) //逐个地将a指向的值逐个地复制过来 { arrayAddr[i]=a[i]; } } //析构函数的类外定义,释放指针型数据a所指向的空间 A::~A() { delete [] arrayAddr; } int A::sum() //获得a指向的数组中下标为i的元素的值 { int s=0; for(int i=0; i<len; i++) //逐个地将a指向的值逐个地复制过来 { s+=arrayAddr[i]; } return s; } int main(){ int b[10]= {75, 99, 90, 93, 38, 15, 5, 7, 52, 4}; A r1(b,10); cout<<"和:"<<r1.sum()<<endl; int c[15] = {18,68,10,52,3,19,12,100,56,96,95,97,1,4,93}; A r2(c,15); cout<<"和:"<<r2.sum()<<endl; return 0; } </span>
(1)什么时候用到拷贝函数?
a.一个对象以值传递的方式传入函数体;
b.一个对象以值传递的方式从函数返回;
c.一个对象需要通过另外一个对象进行初始化。
如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝
(2)什么叫深拷贝?什么是浅拷贝?两者异同?
深如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
(3)深拷贝好还是浅拷贝好?
如果实行浅拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
小结:
不怕不知道就怕不知道,虽然之前学过C#中的深拷贝,但是和C++中的还是有区别的,通过总结让知识更有力量。