拷贝构造
构造函数分为很多种,默认构造,拷贝构造,赋值构造等
重点区分拷贝构造和赋值构造:
拷贝构造和赋值构造都发生在用一个类的某个对象去给另一个对象赋值。
最大的不同是:拷贝构造发生在初始化时,赋值构造不是在初始化赋值。
可以查看该链接区分。
深浅拷贝
理想状态
正常的拷贝都是通过值拷贝,如下代码:
class A{
private:
int a_;
int b_;
public:
A(A& ob):a_(ob.a_),b_(ob.b_){}
A(int m,int n):a_(m),b_(n){}
int a(){return a_;}
int b(){return b_;}
};
int main(){
A a(3,4);
A a1(a);
return 0;
}
这个看起来没有什么问题。也是相当正常的拷贝。
但是当类中含有指针类型属性时,就会出现大麻烦!!
常规出错状态(浅拷贝)
class A{
private:
int a_;
int b_;
int *tmp;
public:
A(A& ob):a_(ob.a_),b_(ob.b_).tmp(ob.tmp){} //注意这是浅拷贝!!
A(int m,int n):a_(m),b_(n){
tmp = new int(5);
}
int a(){return a_;}
int b(){return b_;}
int tmp(){return *tmp;}
};
int main(){
A a(3,4);
A a1(a);
cout << *(a.tmp) << endl; //输出为 5
cout << *(a1.tmp) << endl; //输出为 5
(*(a1.tmp) = 10;
cout << *(a.tmp) << endl; //输出为 10
cout << *(a1.tmp) << endl; //输出为 10
return 0;
}
为什么会出错?
看下面的示意图:
对象a初始化定义在栈空间,构造函数在堆空间申请int = 4的地址为tmp反回;
对象b浅拷贝定义在栈空间,仅拷贝a,b,tmp的值
(也就是a.tmp对应堆空间的地址)。
使用深拷贝
class A{
private:
int a_;
int b_;
int *tmp;
public:
A(A& ob):a_(ob.a_),b_(ob.b_){
int h = *(ob.tmp);
tmp = new int(h);
}
//注意这是深拷贝!!
A(int m,int n):a_(m),b_(n){
tmp = new int(5);
}
int a(){return a_;}
int b(){return b_;}
int tmp(){return *tmp;}
};
int main(){
A a(3,4);
A a1(a);
cout << *(a.tmp) << endl; //输出为 5
cout << *(a1.tmp) << endl; //输出为 5
(*(a1.tmp) = 10;
cout << *(a.tmp) << endl; //输出为 5
cout << *(a1.tmp) << endl; //输出为 10
return 0;
}
此时就变成如下所示的示意图了。
拷贝过来会重新申请一个内存空间。
这样就不会出现改了a1之后a也改了的问题!!