构造函数按照有无参数,可分为有参构造函数和无参构造函数,按照函数类型,可分为普通构造函数和拷贝构造函数。在类中,如果我们不写拷贝构造函数,则编译器编译时会自动帮我们加上一个默认的拷贝构造函数,从而使我们可以使用拷贝对象,若我们写了拷贝构造函数,则系统不会再给我们加默认的拷贝构造函数。
系统默认的拷贝构造函数在拷贝时为浅拷贝,拷贝指针变量时,并不拷贝指针指向的值,而只拷贝指针指向值的地址。此时易出现问题,当我们的类中有堆中数据时(new int),需要我们在析构函数中手动释放掉内存,此时系统会崩溃,原因如下:
test()函数中我们定义的第二个person是通过拷贝函数定义的,而我们没有写拷贝构造函数,使用的为默认的拷贝构造函数,为浅拷贝,拷贝height指针时,并没有在堆区开辟新的地址,而是在栈区开辟了一个地址,其值为height指向值的地址,此时tian.height存储的地址与tian2.height存储的地址相同,均指向最开始有参构造函数开辟的那块内存,存储的数据为“173”。当test()函数执行完的时候,会释放栈区的内存,此时要销毁我们创建的两个对象,将调用类中的析构函数(栈中先进后出,先执行tian2的析构函数),由于我们在析构函数中有delete操作,delete操作会将堆区存储的数据释放(并不会清零,而是变为一个没有意义的数),之后又执行tian的析构函数,又将释放一边堆区存储的数据,从而出现了重复释放的问题,导致系统崩溃。
改进措施为:自己写一个拷贝构造函数(Person(int age, int height)),进行深拷贝,拷贝时直接在堆区开辟新的地址来存储数据。
代码如下:
#include <iostream>
using namespace std;
class Person
{
public:
Person()
{
cout << "无参构造函数" << endl;
}
Person(int age, int height)
{
cout << "有参构造函数" << endl;
this->age = age;
this->height = new int(height);
}
~Person()
{
cout << "析构函数" << endl;
if (height != NULL)
{
delete height;
height = NULL;
}
}
int age;
int* height;
};
void test()
{
Person tian(22,173);
Person tian2(tian);
}
int main()
{
test();
return 0;
}