拷贝构造函数
构造函数可以没有,也可以有多个。
复制构造函数只有一个,不定义编译器自动生成,用户写就使用自定义的复制构造函数
复制构造函数起作用的三种情况
-
用一个对象去初始化同类的另一个对象
<类名> c2(c1); //用c1对象来初始化c2,其中起作用的就是复制构造函数 <类名> c2 = c1; //初始化语句,非复制语句,同上语句
-
函数有一个参数时一个类A的对象时,函数调用时,类A的复制构造函数将被调用。
c++规则函数参数有一个参数时对象,必须调用复制构造函数初始化对象。
class A { int a; A(int b) { a = b; } A(const A &a //复制构造函数 { ... } } void fun(A a1) { ... } int main(void) { A a2; fun(a2); return 0; }
-
函数返回值时某个类的对象,函数返回时,调用类的该类的初始化函数来初始化返回的对象。
对象之间的复制语句不会调用复制构造函数。
C++浅拷贝与深拷贝
浅拷贝
利用编译器提供的拷贝构造函数,会做浅拷贝
浅拷贝带来的问题就死堆区内存的重复释放
案例1:
class Student
{
public:
string name;
int age;
Student(string n_name, int n_age) //构造函数
{
name = n_name;
age = n_age;
}
~Student()
{
}
}
//程序正常输出
void test1(void)
{
Student stu1("solo", 18);
cout << "stu1的年龄 = " << stu1.age << endl;
Student stu2(stu1); //用户没有定义拷贝构造函数,编译器会自动生成一个拷贝构造函数,浅拷贝
cout << "stu的年龄 = " << endl;
}
int main(void)
{
test1();
}
案例2:
class Student
{
public:
string name;
int age;
float *height;
Student(string n_name, int n_age, int n_height) //构造函数
{
name = n_name;
age = n_age;
height = new float(n_height); //在堆区中开辟空间
}
~Student() //析构函数做对象销毁时的一些清理工作
{
if(height != NULL)
{
delete height; //将从堆区申请的内存释放掉
height = NULL;
}
cout << "Student类的析构函数调用" << endl;
}
}
//程序正常输出
void test1(void)
{s
Student stu1("solo", 18, 175);
cout << "stu1的年龄 = " << stu1.age << "身高是 = " << *stu1.height<< endl;
Student stu2(stu1); //使用编译器默认的拷贝构造函数,会进行浅拷贝,stu1的height内容会完完全全复制到stu2的height中,两者的height指向同一块内存
cout << "stu的年龄 = " << "身高是 = " << *stu1.height << endl;
}
//按照先进后出原则test1函数运行结束,stu2对象先销毁,height指向的内存先调用析构函数,销毁了height指向的堆区内存;接着stu1的对象销毁也调用析构函数,height会被重复释放,程序崩溃
int main(void)
{
test1();
}
利用深拷贝解决浅拷贝带来的问题
自己定义拷贝构造函数,解决浅拷贝带来的问题
class Student
{
public:
string name;
int age;
float *height;
Student(string n_name, int n_age, int n_height) //构造函数
{
name = n_name;
age = n_age;
height = new float(n_height); //在堆区中开辟空间
}
~Student() //析构函数做对象销毁时的一些清理工作
{
if(height != NULL)
{
delete height; //将从堆区申请的内存释放掉
height = NULL;
}
cout << "Student类的析构函数调用" << endl;
}
Student(const Student &s) //自定义拷贝构造函数
{
age = s.age;
//height = s.height //编译器默认实现的就是这一句代码
//深拷贝操作
height = new int(*s.height); //解引用s.height的值再存入新开辟的堆区空间中
}
}
//程序正常输出
void test1(void)
{s
Student stu1("solo", 18, 175);
cout << "stu1的年龄 = " << stu1.age << "身高是 = " << *stu1.height<< endl;
Student stu2(stu1); //使用编译器默认的拷贝构造函数,会进行浅拷贝,stu1的height内容会完完全全复制到stu2的height中,两者的height指向同一块内存
cout << "stu的年龄 = " << "身高是 = " << *stu1.height << endl;
}
int main(void)
{
test1(); //程序正常输出
}
注意:
如果有属性的内存在堆区开辟,一定要自定义拷贝构造函数,防止浅拷贝带来的问题