c++拷贝构造函数(深拷贝、浅拷贝)——转
拷贝构造函数:
拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类的一个引用变量,该参数是const类型,不可变的。例如:类A的拷贝构造函数的形式为A(A& x)。当用一个已经初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝函数就会被自动调用。也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况会自动调用拷贝构造函数:
1、一个对象以值传递的方式传入函数体
2、一个对象以值传递的方式从函数返回,如下:
#include <iostream>
using namespace std;
class B
{
public:
B(){cout<<"构造函数B"<<endl;}
B(int i):data(i){cout<<"构造函数B"<<" "<<data<<endl;}
B play(B b){return b;}
~B(){cout<<"析构函数B"<<endl;}
private:
int data;
};
int main()
{
B temp;
temp.play(5);
return 0;
}
3、一个对象需要通过另一个对象进行初始化
如果在类中没有显示地声明一个拷贝构造函数,那么编译器会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的拷贝。自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。
深拷贝和浅拷贝:
在某些情况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝(位拷贝又称浅拷贝),也就是把对象里面的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员也指向同一块内存。这就出现了问题:把B内存释放了,这时A内的指针就是野指针了,出现运行错误。
深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之没有重新分配资源就是浅拷贝。
浅拷贝:如果复制的对象中引用了一个外部内容(例如分配在堆上的数据),那么在复制这个对象的时候,让新旧两个对象指向同一个外部内容,就是浅拷贝。(指针虽然复制了,但所指向的空间内容并没有复制,而是由两个对象共用,两个对象不独立,删除空间存在)
#include <iostream> #include <string.h> using namespace std; class Example { private: int a; char *str; public: Example() { cout<<"调用构造函数"<<endl; } ~Example() { cout<<"调用析构函数"<<endl; } Example(int b) { a=b;
cout<<"调用构造函数"<<endl;
}
Example(const Example& example)//自定义拷贝构造函数
{
a=example.a;
}
void show()
{
cout<<a<<endl;
}
};
int main()
{
Example a1(10);
Example a2=a1;
a2.show();
return 0;
}
输出:
调用构造函数
10
调用析构函数
调用析构函数
深拷贝:如果在复制这个对象的时候为新对象制作了外部对象的独立复制,就是深拷贝。
#include <iostream> #include <string.h> using namespace std; class Example { private: int a; char *str; public: Example() { cout<<"调用构造函数"<<endl; } ~Example() { delete str; cout<<"调用析构函数"<<endl; } Example(int b,char* e_str) { a=b; str=new char[b]; strcpy(str,e_str);
cout<<"调用构造函数"<<endl;
}
Example(const Example& example)//自定义拷贝构造函数
{
a=example.a;
str=new char[a];//深拷贝
if(str!=0)
strcpy(str,example.str);
}
void show()
{
cout<<str<<endl;
}
};
int main()
{
Example a1(10,"Hello");
Example a2=a1;
a2.show();
return 0;
}
输出:
调用构造函数
Hello
调用析构函数
调用析构函数