C++---构造函数与析构函数 深拷贝与浅拷贝

简单认知

构造函数:初始化对象成员属性,编译器自动调用
析构函数:对象销毁前自动调用,用于释放内存等一些清理工作

#include <iostream>
using namespace std;

class Dog{
public:
    Dog()
    {
       cout<<"构造函数调用"<<endl;
    }
    ~Dog()
    {
        cout<<"析构函数调用"<<endl;
    }

};

void example()
{
    Dog dog;
}

int main()
{
    example();

    return 0;
}

输出结果
在这里插入图片描述

分类

可分为有参构造和无参构造
或可分为普通构造和拷贝构造
一般情况下,系统会默认给类添加一个空实现的构造函数,空实现的析构函数和对属性进行拷贝的拷贝构造函数

有参构造和拷贝构造简单用法例:

#include <iostream>
using namespace std;

class Dog{
public:
    Dog()
    {
       cout<<"构造函数调用"<<endl;
    }
    Dog(int a)
    {
        cout<<"有参构造的调用"<<endl;
    }
    ~Dog()
    {
        cout<<"析构函数调用"<<endl;
    }
    Dog(const Dog &d)
    {
        cout<<"拷贝构造函数调用"<<endl;
    }
};

void example()
{
    Dog dog(1);//有参构造定义时传入参数
    Dog dog1(dog);//拷贝构造定义时传入对象
}

int main()
{
    example();

    return 0;
}

结果
在这里插入图片描述
在用户定义了有参构造并且在创建对象的时候传入参数之后,无参构造不再调用

深拷贝与浅拷贝

浅拷贝

#include <iostream>
#include <string>
using namespace std;

class Dog{
public:
    Dog()
    {
       cout<<"构造函数调用"<<endl;
    }
    Dog(string color)
    {
        my_color = color;
       // cout<<"有参构造的调用"<<endl;
    }
    ~Dog()
    {
       // cout<<"析构函数调用"<<endl;
    }

    string my_color;
};

void example()
{
    Dog dog("white");//有参构造定义时传入参数
    cout<<"dog的颜色为:"<<dog.my_color<<endl;
    Dog dog1(dog);//拷贝构造定义时传入对象
    cout<<"dog1的颜色为:"<<dog1.my_color<<endl;
}

int main()
{
    example();

    return 0;
}

结果
在这里插入图片描述
我们并没有定义拷贝构造函数,但是当我们定义dog1对象并把dog作为参数传进去的时候,就相当于调用自带默认的拷贝构造函数,依照传进去的dog简单拷贝了一个新的对象dog1,所以dog1的颜色也是白色,这就是浅拷贝。

此时我们新增一个属性年龄

#include <iostream>
#include <string>
using namespace std;

class Dog{
public:
    Dog()
    {
       cout<<"构造函数调用"<<endl;
    }
    Dog(string color,int age)
    {
        my_color = color;
        my_age = new int(age);//指针接收创建在堆区的数据
       // cout<<"有参构造的调用"<<endl;
    }
    ~Dog()
    {
       // cout<<"析构函数调用"<<endl;
    }
    
    string my_color;
    int * my_age;
};

void example()
{
    Dog dog("white",2);//有参构造定义时传入参数
    cout<<"dog的颜色为:"<<dog.my_color<<'\t'<<"dog的年龄为:"<<*dog.my_age<<endl;
    Dog dog1(dog);//拷贝构造定义时传入对象
    cout<<"dog1的颜色为:"<<dog1.my_color<<'\t'<<"dog1的年龄为:"<<*dog1.my_age<<endl;
}

int main()
{
    example();

    return 0;
}

输出结果
在这里插入图片描述
没有问题
这里面我们在堆区申请了一块内存没有释放,如果我们在析构函数函数去释放my_age的时候,会发现程序会崩溃。
原因:
当我们在定义dog的时候,一共有两个属性,一个是颜色,一个是年龄,其中年龄是在堆区创建的指针类型,当我们利用浅拷贝定义了dog1对象的时候,dog1年龄指针也指向了与dog年龄指针一样的地址,所以如果在析构函数函数中去释放这一块内存,相当于释放两次一样的内存,程序出错。
这是浅拷贝带来的问题,堆区内存重复释放
利用深拷贝来解决,自定义拷贝构造函数,重新申请内存接收my_age

#include <iostream>
#include <string>
using namespace std;

class Dog{
public:
    Dog()
    {
       cout<<"构造函数调用"<<endl;
    }
    Dog(string color,int age)
    {
        my_color = color;
        my_age = new int(age);//指针接收创建在堆区的数据
       // cout<<"有参构造的调用"<<endl;
    }
    ~Dog()
    {
        if(my_age != NULL)
        {
            delete my_age;
            my_age = NULL;
        }
       // cout<<"析构函数调用"<<endl;
    }

    Dog(const Dog &d)
    {
        my_color = d.my_color;
        my_age = new int(*d.my_age);//重新申请内存接收拷贝的指针
    }
    string my_color;
    int * my_age;
};

void example()
{
    Dog dog("white",2);//有参构造定义时传入参数
    cout<<"dog的颜色为:"<<dog.my_color<<'\t'<<"dog的年龄为:"<<*dog.my_age<<endl;
    Dog dog1(dog);//拷贝构造定义时传入对象
    cout<<"dog1的颜色为:"<<dog1.my_color<<'\t'<<"dog1的年龄为:"<<*dog1.my_age<<endl;
}

int main()
{
    example();

    return 0;
}
发布了14 篇原创文章 · 获赞 30 · 访问量 8733

猜你喜欢

转载自blog.csdn.net/weixin_43086497/article/details/104873190
今日推荐