• 【C++】之类和对象 - 初始化列表


    目录

    一.初始化列表的本质

    二.使用初始化列表


    引出:对象在被编译器创建出来时,编译器给对象开辟好空间,那么对象中的成员变量是何时被定义的呢?编译器在创建对象时,会自动调用构造函数,调用构造函数的本质是什么?

    一.初始化列表的本质

    1. class Time
    2. {
    3. public:
    4. //显示定义一个有参的构造函数,运行报错
    5. Time(int hour)
    6. {
    7. _hour = hour;
    8. }
    9. //显式定义一个全缺省的默认构造函数,运行可以通过
    10. //Time(int hour = 0)
    11. //{
    12. // _hour = hour;
    13. // cout << "调用Time全缺省构造" << endl;
    14. //}
    15. private:
    16. int _hour;
    17. };
    18. class Date
    19. {
    20. public:
    21. Date(int year, int month, int day, int hour)
    22. {
    23. _year = year;
    24. _month = month;
    25. _day = day;
    26. Time t(hour);
    27. _t = t;
    28. }
    29. private:
    30. int _year;
    31. int _month;
    32. int _day;
    33. Time _t;
    34. };
    35. int main()
    36. {
    37. Date d1(2022, 8, 10, 24);
    38. return 0;
    39. }

    结果:报错

    默认构造分三类:编译器生成,显式定义无参,显式定义全缺省

    这里报错的原因:Date的构造函数对于内置类型不做处理,对于自定义类型调用其自己的默认构造函数,可以看到,由于Time类中我们显示写了有参构造,编译器就不会生成,自然就没有默认构造。如果我们用int hour = 0这样全缺省的构造就可以被调用了并且调用之后是我们想要的结果。

    通过这一现象,可以进一步思考,为什么一定要调用默认构造?我显示定义的有参构造难道不可以直接调用吗?这时需要引出初始化列表这一概念。回到了最开始的问题,对象内的成员变量究竟是何时被定义的? 

    Time的全缺省构造是被调用了两次的。因为Time的全缺省构造既是默认构造,又是有参构造。

    这里就解释了为什么一定要调用默认构造!每个构造函数都隐式的拥有一个初始化列表,而对象内的成员变量就是在初始化列表中被定义的

    以上这里的调用逻辑是:

    ---> 编译器先创建一个Date类的对象d1,编译器自动调用Date构造函数

    这时(构造函数对内置类型不处理,对自定义类型调用自己的默认构造函数)本质就是在初始化列表中给定义的成员变量初始化,由于我们不显式的去写的话,也就没有参数,只能是隐式的调用默认构造函数,也就不需要参数。

    ---> 初始化列表调用一次默认构造函数(也就是Time的全缺省构造)

    ---> 之后在Time t(hour)时,再调用一次Time全缺省构造

    可以看到对于自定义类型的成员变量类内初始化时:

            1.会调用两次构造 + 一次拷贝

    (一次在初始化列表调用,一次在创建临时变量调用,一次临时变量的拷贝)

            2.自定义类型一定要有自己的默认构造

            3.代码过于繁琐

    对于以上的总结:

    1.初始化列表可以认为是成员变量定义的地方

    2.类内初始化成员变量,其实严格意义上不是初始化而是赋值,因为成员变量在初始化列表被定义,被定义的同时也就被初始化了。

    3.对于内置类型在哪里初始化都行,对于自定义类型推荐使用初始化列表

    二.使用初始化列表

    1. class Time
    2. {
    3. public:
    4. Time(int hour)
    5. {
    6. _hour = hour;
    7. }
    8. private:
    9. int _hour;
    10. };
    11. class Date
    12. {
    13. public:
    14. Date(int year, int month, int day, int hour)
    15. :_year(year),_month(month),_day(day),_t(hour)
    16. {
    17. }
    18. private:
    19. int _year;
    20. int _month;
    21. int _day;
    22. Time _t;
    23. };
    24. int main()
    25. {
    26. Date d1(2022, 8, 10, 24);
    27. return 0;
    28. }

    注意

    1.每个变量只能在初始化列表出现一次

    2.以下成员必须在初始化列表初始化

            引用成员变量

            const成员变量

            自定义类型成员变量(没有默认构造时)

    引用与const成员变量有一个共同特点:必须在变量定义的地方初始化!而不能定义之后再赋值!

    而自定义类型成员变量在初始化列表隐式定义时必须调用默认构造

    3.成员变量定义的顺序不是初始化列表中的顺序,而是在类中声明的顺序

    4.由于C++默认构造对于内置类型不做处理而有可能导致为随机值,之后打了一个补丁,在变量声明的地方可以加缺省值,这个补丁的本质就是在初始化列表给内置类型加上默认值

  • 相关阅读:
    对Python3.8配置OpenCV4.5.5中
    【探索AI】三十二-计算机视觉(七)实践项目与案例分析
    liteos连接器脚本隐藏的指针问题
    学习如何编码
    asp.net在线医疗系统VS开发sqlserver数据库web结构c#编程计算机网页项目
    百度api搜索,跳过安全验证
    【GlobalMapper精品教程】027:路径剖面和和视线工具的使用
    牛客网最新Java面试通关八股文手册,花点耐心每天刷上10道题,挑战一下年薪50W!
    PCtoLCD2002 图片取模教程
    JS实现异步的方法
  • 原文地址:https://blog.csdn.net/Hello_World_213/article/details/126271263