1、 深浅拷贝是指深拷贝构造函数和浅拷贝构造函数。构造函数总共有三类:无参构造函数、有参数构造函数、拷贝构造函数。
2、 当有属性在堆区开辟的,一定要提供拷贝构造函数,防止浅拷贝带来的问题。(堆区需要手动的清除内存,如果没有去除,系统在结束后会去除。但是析构函数在系统结束之前执行,浅拷贝导致析构函数运行错误)
1、概念
- 无参构造函数,又称位默认构造函数,默认构造函数的意思是编译器会自动生成,不需要人工的手写。默认构造函数的要求是:函数名与类名相同,没有参数,没有返回值。
- 有参构造函数:有参数传递的构造函数。
- 拷贝构造函数:使用另一个对象实例化自己的对象。具体见下面的代码。
2、浅拷贝
没有书写拷贝构造函数时,编译器使用默认拷贝构造函数,就是下面的值传递的构造。我们一般会在有参构造函数做如下的赋值操作:
Person()
{
public:
int age;
int * weight;
//有参构造函数
Person(int n_age,int n_weight)
{
age=n_age;
weight=n_weight;
}
Person(const Person &p)
{
age=p.age;
weight=p.weight;
}
}
void test()
{
//初始化对象p1,年龄20,体重140
Person p1(20,140);
//使用p1对象赋值给p2,相当于把p1对象拷贝给p2
Person p2(p1);
}
int main()
{
test();
return 0;
}
- 注意上述的age=n_age;和weight=n_weight;语句,这是一个值传递。p2对象由p1对象初始化,也就是我们说的浅拷贝。
- 当函数结束运行时,p1和p2对象都要进行析构,p1先创建的,所以后析构。因此其过程就是p1构造函数->p2构造函数->p2析构函数->p1析构函数。浅拷贝带来的问题是p2对象weight和p1对象的weight指向了同一个位置Q。p2析构函数将p2对象weight指向的位置Q释放了,p1析构函数运行时将p1对象weight指向的位置Q释放,可是Q现在已经不存在了,所以发生错误,这就是浅拷贝带来的问题。
3、深拷贝解决浅拷贝的问题
- 解决思路:手写拷贝构造函数,在拷贝构造函数中,为*weight通过new重新申请一个堆区内存。这样就不会两个指针指向同一个位置了。
Person()
{
int age;
int *weight;
Person(int n_age,int n_weight)
{
age=n_age;
weight = new int(n_weight);
}
//手动书写拷贝构造函数
Person(const Person &p)
{
age=n_age;
//在拷贝一个对象时,有属性是在堆区内存的,
//需要写拷贝构造函数
weight=new int(*p.weight) ;
}
~Person()
{
//这里可以写一个析构函数
if(p.weight!=NULL)
{
del weight;
weight=NULL;
}
}
}
void test()
{
Person p1(10,120);
cout<<"年龄:"<<p1.age<<"体重:"<<p1.weight<<endl;
Person p2(p1);
cout<<"年龄:"<<p2.age<<"体重:"<<p2.weight<<endl;
}
int main()
{
test();
return 0;
}
4、扩展
如果写了有参构造函数,那么C++将不产生默认构造函数,但是或有默认的拷贝构造函数。
如果写了拷贝构造函数,那么C++不提供构造函数。