• 【C++】之类和对象 - 构造与析构


    目录

    一.构造函数(无参&&有参)

    1.概念

    2.特性

    3.代码

    4.默认构造函数

    二.析构函数

    1.概念

    2.特性:

    3.有自定义类型的析构调用顺序

    三.拷贝构造函数

    1.概念

    2.特性

    3.拷贝构造的参数问题

    4.编译器自动生成的拷贝构造

    5.哪些场景会调用拷贝构造


    一.构造函数(无参&&有参)

    1.概念

    构造函数是一个特殊的成员函数,名字与类名相同,创建类对象时由编译器自动调用,并且在对象的整个生命周期内只调用一次

    2.特性

    1).构造函数,并不开辟空间创建对象,而是对已经创建的对象初始化

    2).函数名与类名相同

    3).无返回值

    4).对象实例化时编译器自动调用

    5).构造函数支持重载

    6).对内置类型(char,int,double...)不做处理,对自定义类型,自动调用自定义类型的构造函数

    3.代码

    1. class Date
    2. {
    3. public:
    4. //1.无参构造函数(如果不写构造函数,则系统默认生成)
    5. Date()
    6. {
    7. }
    8. //2.有参构造函数(与无参构造函数发生重载)
    9. Date(int year, int month, int day)
    10. {
    11. _year = year;
    12. _month = month;
    13. _day = day;
    14. }
    15. //3.带缺省参数的有参构造
    16. //Date(int year, int month = 3, int day = 10)
    17. //{
    18. // _year = year;
    19. // _month = month;
    20. // _day = day;
    21. //}
    22. private:
    23. int _year;
    24. int _month;
    25. int _day;
    26. };
    27. int main()
    28. {
    29. Date d1;//调用无参构造 注意:不要写成Date d1()这样会被当作函数声明
    30. Date d2(2022, 8, 7);//调用有参构造
    31. return 0;
    32. }

    4.默认构造函数

    一般把默认构造函数分为三类:

            编译器自动生成的无参构造函数

            全缺省的有参构造函数

            我们自己写的无参构造函数

    默认构造函数只能有一个,本质原因就是如果有多个的话,无法发生重载

    代码:

    所以当我们没有写构造函数的时候,编译器自动生成的构造函数有什么用呢?

    作用就在于,编译器默认生成的是构造函数,只要是构造函数,如果有自定义类型,就会对自定义类型调用其自己的默认构造函数。

    构造函数对内置类型不做处理,我们可以看到调用编译器生成的构造时,仍然还是随机值

    C++11中对于构造函数内置类型不初始化这一缺陷打了一个补丁:

    内置类型成员在声明时,可以以缺省值的方式给默认值

    1. class Date
    2. {
    3. public:
    4. private:
    5. //这里用给缺省值的方式,来给内置类型设置默认值,注意这里仍然是声明
    6. int _year = 2022;
    7. int _month = 8;
    8. int _day = 7;
    9. };
    10. int main()
    11. {
    12. Date d1;
    13. return 0;
    14. }

    二.析构函数

    1.概念

    与构造函数功能相反,构造函数完成了对刚创建的对象的初始化,析构函数完成了对即将销毁的对象的数据释放

    析构函数不是完成对对象本身的销毁,对象销毁与对象创建一样,由编译器完成,对象在销毁时自动调用析构函数,完成对象中的资源清理

    2.特性:

    1).析构函数名是在类名之前加上~

    2).无参无返回值

    3).一个类只能有一个析构函数

    4).若没有显式定义则系统自动生成默认析构函数

    5).对象生命周期结束时,编译器自动调用析构

    6).如果有自定义类型,该类析构函数会自动调用自定义类型中的析构函数

    3.有自定义类型的析构调用顺序

    1. class Time
    2. {
    3. public:
    4. Time()
    5. {
    6. _hour = 1;
    7. _minute = 1;
    8. _second = 1;
    9. cout << "调用Time构造函数" << endl;
    10. }
    11. ~Time()
    12. {
    13. cout << "调用Time析构函数" << endl;
    14. }
    15. private:
    16. int _hour;
    17. int _minute;
    18. int _second;
    19. };
    20. class Date
    21. {
    22. public:
    23. Date()
    24. {
    25. _year = 2022;
    26. _month = 8;
    27. _day = 7;
    28. cout << "调用Date构造函数" << endl;
    29. }
    30. ~Date()
    31. {
    32. cout << "调用Date析构函数" << endl;
    33. }
    34. private:
    35. int _year;
    36. int _month;
    37. int _day;
    38. Time _t;
    39. };
    40. int main()
    41. {
    42. Date d1;
    43. return 0;
    44. }

    构造顺序:首先编译器创建出对象d1,在给d1初始化时,需要先调用对象t的构造,t初始化好之后,再调用Date构造 

    析构顺序:编译器不会直接去调用Time析构,而是先调用Date析构,Date析构在清理数据时发现,还需要清理对象t,然后接着调用Time析构

    如果没有在堆区创建的对象,一般直接使用默认生成的就ok了,如果有需要释放的数据空间则一定要显示去写析构函数

    此外,还要记住一点,后构造的先析构

    三.拷贝构造函数

    1.概念

    拷贝构造是构造函数的一种,在对象创建时,将一个对象完整的拷贝给另一个对象

    拷贝构造函数是对一个对象的初始化,而不是赋值!

    2.特性

    1).拷贝构造函数是构造函数的一个重载形式

    2).参数只有一个且必须是类类型对象的引用,如果以传值的方式将直接报错

    3).如果没有显示定义,编译器会自动生成默认的拷贝构造函数(浅拷贝)

    3.拷贝构造的参数问题

    参数必须是类类型对象的引用

    1. //因为仅仅只是拷贝,而又必须使用传引用的方式
    2. //防止因误操作将原先数据修改,一般在前面加上const
    3. Date(const Date& d)
    4. {
    5. *this = d;
    6. }

    如果直接传值可不可以呢,例如Date(const Date d),这样不行,会发生无限递归调用拷贝构造

    ~~如果是传值

    因为要调用拷贝构造,但每次传值的本质就是拷贝(编译器新创建一个变量然后需要调用拷贝构造来初始化这个变量)就又需要调用拷贝构造,这样一直循环下去

    ~~如果是传引用

    传引用的本质就是传地址,传地址不需要调用拷贝构造

    4.编译器自动生成的拷贝构造

    编译器自动生成的拷贝构造是一种浅拷贝

    对于内置类型按照字节直接拷贝(浅拷贝)对于自定义类型调用其自己的拷贝构造

    当没有涉及到资源申请的时候,拷贝构造是否显式去写都可以,一旦涉及到malloc或者new,那么拷贝构造是一定要写的,如果不写,就用编译器生成的那一定是浅拷贝,本来1个指针指向一块空间,拷贝之后并没有拷贝空间而是直接拷贝了一个指针,2个指针指向同一个空间,很容易出问题

    5.哪些场景会调用拷贝构造

    1).用类实例化对象,且用已有对象初始化

    2).函数传参类型为类的类型

    3).函数返回值为类的类型

  • 相关阅读:
    java MessageDigest 实现加密算法
    【ADB】蓝牙总结
    前端性能优化 - 虚拟滚动
    hive-join
    阿里云杨国彦:云上护航,陪伴成长
    WLAN与WiFi各是什么意思有什么区别
    回溯专题——day33
    Android webView JS 之间的交互
    Vue学习第18天——Vue中的过度与动画效果的使用与案例
    并联四足机器人项目开源教程(一)--- 机器人学导论的学习
  • 原文地址:https://blog.csdn.net/Hello_World_213/article/details/126210640