析构函数&&拷贝构造函数

举报
芒果_Mango 发表于 2022/07/31 23:11:29 2022/07/31
【摘要】 大家好,我是芒果,一名非科班的在校大学生。对C/C++、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流作者简介:CSDN C/C++领域新星创作者https://blog.csdn.net/chuxinchangcun?type=blog掘金LV3用户 https://juejin.cn/us...

大家好,我是芒果,一名非科班的在校大学生。对C/C++、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

作者简介:


3.析构函数

前面通过构造函数的学习,我们知道一个对象时怎么来的,那一个对象又是怎么没呢的? 析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而 对象在销毁时会自动调用析构函数,完成对象的一些资源清理工作


3.2 特性

析构函数是特殊的成员函数。

其特征如下:

  1. 析构函数名是在类名前加上字符~
  2. 无参数无返回值。
  3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数

一个类有且只有一个析构函数,因为析构函数不支持函数重载(析构函数是无参数的所以不支持)


对于日期类:没有资源需要清理,所以Date类不实现析构函数也是可以的

typedef int DataType;
class SeqList
{
public :
    //构造函数
    SeqList (int capacity = 10)
    {
        _pData = (DataType*)malloc(capacity * sizeof(DataType));
        assert(_pData);
        _size = 0;
        _capacity = capacity;
    }
    //析构函数
    ~SeqList()
    {
        if (_pData)
        {
            free(_pData ); // 释放堆上的空间
            _pData = NULL; // 将指针置为空
            _capacity = 0;
            _size = 0;
        }
    }
private :
    int* _pData ;
    size_t _size;
    size_t _capacity;
};
int main()
{
    SeqList s1(20);
    SeqList s2;
    return 0;
}

image-20220116214738447

构造时:s1先构造

析构时:s2先析构 。析构是相反的顺序,因为栈是后进先出,先把s2清理掉。


  1. 关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认 析构函数,对会自定类型成员调用它的析构函数。
class String
{
public:
    String(const char* str = "jack")
    {
        _str = (char*)malloc(strlen(str) + 1);
        strcpy(_str, str);
    }
    ~String()
    {
        cout << "~String()" << endl;
        free(_str);
    }
private:
    char* _str;
};
class Person
{
private:
    String _name;
    int _age;
};
int main()
{
    Person p;
    return 0;
}

image-20220116215400540

如果我们不写默认生成析构函数,和构造函数类似,对于内置类型成员变量不做处理,对于自定义类型成员变量会去调用它的析构函数.


4.拷贝构造函数

4.1 概念

在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎。

image-20220116172329320


那在创建对象时,可否创建一个与一个对象一某一样的新对象呢? 构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类型对象 创建新对象时由编译器自动调用。

//例如
Date(Date d) //传值传参err
{};
Date(const Date& d)//传引用
{};

4.2 特征

拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。

class Date
{
public:
    //默认构造函数 -全缺省构造函数
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    //拷贝构造函数
    //加上const修饰,防止写错了 d._year = _year
    Date(const Date& d)
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d1;
    Date d2(d1);
    return 0;
}

若采用的是传值传参:会引发无穷递归调用

调用拷贝构造,需要先传参数,传值传参又是一个拷贝构造->调用拷贝构造,需要先传参数,传值传参又是一个拷贝构造…

image-20220116172453852


传值传参为什么是拷贝构造?

image-20220116221425406


  1. 若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷 贝,这种拷贝我们叫做浅拷贝,或者值拷贝。

字节序拷贝:把我的每个字节依次拷贝给你

class Date
{
public:
    //构造函数
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d1;
    // 这里d2调用的系统生成的默认拷贝构造完成拷贝,d2和d1的值也是一样的。
    Date d2(d1);
    return 0;
}

image-20220116221748164


浅拷贝可能存在问题:

例如:

class Stack
{
public:
    //默认构造函数
    Stack(int capacity = 4)
    {
        _a = (int*)malloc(sizeof(int) * _capacity);
        if (_a == nullptr)
        {
            cout << "malloc fail\n" << endl;
            exit(-1);
        }
        _top = 0;
        _capacity = capacity;
    }
    void Push(int x) {};
    //析构函数
    ~Stack()
    {
        free(_a);
        _a = nullptr;
        _top = _capacity = 0;
    }
private:
    int* _a;
    int _top;
    int _capacity;
};
​
int main()
{
    Stack s1;
    //拷贝复制
    Stack s2(s1);
    return 0;
}

image-20220116225315870

分析:

image-20220116225529277


总结:

默认生成拷贝构造:

1.内置类型成员,会完成按字节序拷贝(浅拷贝)

2.自定义类型成员,会调用它自己类的拷贝构造

拷贝构造我们不写时,生成的默认拷贝构造函数对于内置类型和自定义类型都会拷贝处理,但是处理细节不一样,这个和构造函数和析构函数是不一样的。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。