C++拷贝构造函数&浅拷贝和深拷贝

拷贝构造函数

构造函数可以没有,也可以有多个。

复制构造函数只有一个,不定义编译器自动生成,用户写就使用自定义的复制构造函数

复制构造函数起作用的三种情况

  • 用一个对象去初始化同类的另一个对象

    <类名> 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();       //程序正常输出
}

注意:

如果有属性的内存在堆区开辟,一定要自定义拷贝构造函数,防止浅拷贝带来的问题

猜你喜欢

转载自blog.csdn.net/qq_36413982/article/details/105502288