• 【C++--类和对象】构造函数&&析构函数


    先来介绍一下类和对象中的六个默认成员函数:构造函数,析构函数,拷贝构造,赋值重载,普通对象取地址重载,const修饰对象取地址重载

    这六类函数都是在我们没有显示定义的时候,编译器会自己生成的函数。而在我们显式定义以后编译器则不会处理。

    构造函数和析构函数不是创建和销毁对象(对象存在于栈区,随着函数栈帧创建和销毁),而是初始化和清理工作。

    构造函数 

    一般是public的

    是一种特殊的成员函数,

    1、函数名与类名相同

    2、没有返回值 不用写void

    3、对象实例化的时候自动调用

    4、支持重载

    5、如果类里边没有显式定义构造函数编译器将会自动生成一个无参构造函数(默认构造函数),如果我们显式定义了编译器将不会生成默认构造函数

    • 默认构造

    不传参就可以调用的函数就是默认构造函数,不一定是我们不写编译器自动生成,一共有三种情况。

    默认构造函数的三种形式:无参构造函数,全缺省构造函数,编译器默认生成的构造函数都是默认构造函数。

    这三者有且只能有一个(只能存在一个默认构造函数)

    【1】调用无参构造:

    1. #include
    2. using namespace std;
    3. class Data
    4. {
    5. public:
    6. void Print()//会隐含一个this指针,指向对应的对象
    7. {
    8. cout<<_year<<"-"<<_month<<"-"<<_day<
    9. }
    10. //我们不写,编译器自动生成一个
    11. //无参构造函数
    12. Data()
    13. {
    14. cout<<"Data();"<
    15. _year=2023;
    16. _month=1;
    17. _day=1;
    18. }
    19. //全缺省构造函数
    20. /*Data(int year=2020,int month=2,int day=2)
    21. {
    22. cout<<"Data(int year=2020,int month=2,int day=2);"<
    23. _year=year;
    24. _month=month;
    25. _day=day;
    26. }*/
    27. private:
    28. int _year=1;
    29. int _month=1;
    30. int _day=1;
    31. };
    32. int main()
    33. {
    34. Data d1;
    35. d1.Print();
    36. return 0;
    37. }

    运行结果:

    【2】调用全缺省构造

    1. #include
    2. using namespace std;
    3. class Data
    4. {
    5. public:
    6. void Print()//会隐含一个this指针,指向对应的对象
    7. {
    8. cout<<_year<<"-"<<_month<<"-"<<_day<
    9. }
    10. //我们不写,编译器自动生成一个
    11. //无参构造函数
    12. /*Data()
    13. {
    14. cout<<"Data();"<
    15. _year=2023;
    16. _month=1;
    17. _day=1;
    18. }*/
    19. //全缺省构造函数
    20. Data(int year=2020,int month=2,int day=2)
    21. {
    22. cout<<"Data(int year=2020,int month=2,int day=2);"<
    23. _year=year;
    24. _month=month;
    25. _day=day;
    26. }
    27. private:
    28. int _year=1;
    29. int _month=1;
    30. int _day=1;
    31. };
    32. int main()
    33. {
    34. Data d1;
    35. d1.Print();
    36. return 0;
    37. }

    运行结果:

    【3】调用编译器自己生成的默认构造 (不写构造函数)

    1. #include
    2. using namespace std;
    3. class Data
    4. {
    5. public:
    6. void Print()//会隐含一个this指针,指向对应的对象
    7. {
    8. cout<<_year<<"-"<<_month<<"-"<<_day<
    9. }
    10. //我们不写,编译器自动生成一个
    11. //无参构造函数
    12. /*Data()
    13. {
    14. cout<<"Data();"<
    15. _year=2023;
    16. _month=1;
    17. _day=1;
    18. }*/
    19. //全缺省构造函数
    20. /*Data(int year=2020,int month=2,int day=2)
    21. {
    22. cout<<"Data(int year=2020,int month=2,int day=2);"<
    23. _year=year;
    24. _month=month;
    25. _day=day;
    26. }*/
    27. private:
    28. //给缺省值,当调用的是编译器自己生成的默认构造时会使用此缺省值
    29. int _year=1;
    30. int _month=1;
    31. int _day=1;
    32. };
    33. int main()
    34. {
    35. Data d1;
    36. d1.Print();
    37. return 0;
    38. }

    运行结果:

    1)如果不给缺省值,得到的是随机值(有的编译器也会进行处理,进行不同的初始化)

    2)如果给了缺省值,则会按缺省值进行初始化对象

    就相当于

    C++规定:当我们不写构造函数时,编译器生成默认构造函数

    【1】内置类型编译器不做处理,在声明的时候可以给缺省值,给了会进行初始化。(编译器不一定都会初始化内置类型成员,没有规定一定要进行处理) (就像上面写到的给_year,_month,_day缺省值,会进行对应的初始化处理)

    【2】自定义类型会处理,会去调用它的默认构造。

    可以算是c++的一个不足之处。(内置类型没有自动处理)

    得出结论:

    1、一般情况下,类里边有内置类型成员,默认构造函数需要我们自己写(否则会出现随机值的情况)

    2、如果类里边全部都是自定义类型的成员,可以考虑让编译器自己生成(我们自己不用写,编译器调用默认构造函数)

    3、如果类里边内置类型和自定义类型同时存在,内置类型不会处理,自定义类型一定会处理

    (初始化的时候,有些编译器可能在没有写构造函数情况下,处理其中的内置类型,但这只是编译器的个性化行为)(所以必须得自己写默认构造)

    注意:
    1. class Data
    2. {
    3. public:
    4. Data()
    5. {
    6. }
    7. Data(int year=1,int month=1,int day=1)
    8. {
    9. }
    10. //两者可以同时存在,构成重载
    11. //但是在无参调用的时候,例如主函数中的Data d1;就会出现问题
    12. //因为不知道调用的是哪一个函数,两者都可以
    13. private:
    14. int _year=1;
    15. int _month=1;
    16. int _day=1;
    17. //这种写法C++11标准下是支持的,这不是初始化,仅仅只是声明
    18. //给的默认缺省值,是给编译器生成默认构造函数用的
    19. };

    构造函数的调用和普通函数也是有所区别的,

    1. int main()
    2. {
    3. //构造函数的调用
    4. Data d1;//对象不加列表
    5. Data d2(1,1,1);//对象+参数列表
    6. Data d2();//但是不可以这么写(在无参的情况下+括号)与函数声明冲突
    7. return 0;
    8. }

    析构函数

    1、函数名在类名的前面加上~

    2、无参无返回值 =》因此不能重载。

    3、一个类只有一个,若显式定义系统不生成;若未显式定义,系统自动生成。

    4、生命周期结束自动调用

    函数的生命周期结束之后,自动调用;一般不会造成内存泄漏(学到后面可能会造成内存泄露,但智能指针可解决此类问题,后续再说)

    • 默认析构函数(编译器自动生成的析构函数):

    a、内置类型成员不做处理

    一般内置类型存储在栈上,不需要我们手动释放

    b、自定义类型会调用他的析构函数

    堆上的资源需要我们手动释放

    1、需要写析构:一般有动态申请的资源,需要显式写析构函数(eg:栈 需要显式写析构函数 )

    2、不需要写析构:

    a、没有动态申请的资源(没有malloc之类)

    eg:日期类 不需要写析构(都是内置类型,没有动态申请资源)

    b、需要释放资源的成员都是自定义类型 这两种情况是需要释放的

  • 相关阅读:
    ArcGIS 制作科幻风格的轮廓线
    如何使用Redux与React进行状态管理?
    12 款小众宝藏AI工具,90% 的开发者不了解
    【python基础(三)】操作列表:for循环、正确缩进、切片的使用、元组
    脑机接口003 | 马斯克称已实现与云端的虚拟自己对话,相关概念股份大涨
    计算机基础知识47
    通过JDBC连接MySQL
    LSM Tree 深度解析
    论文解读(DCN)《Towards K-means-friendly Spaces: Simultaneous Deep Learning and Clustering》
    ardupilot 关于设备车Rover的学习《2》------如何解锁
  • 原文地址:https://blog.csdn.net/awww224112/article/details/132774404