• 初始化列表


    一、初始化和实例化

    类的初始化:是完成程序执行前的准备工作。在这个阶段,静态的(变量,方法,代码块)会被执行。同时在会开辟一块存储空间用来存放静态的数据初始化只在类加载的时候执行一次

    类的实例化:是指创建一个对象的过程。这个过程中会在中开辟内存,将一些非静态的方法,变量存放在里面。在程序执行的过程中,可以创建多个对象,既多次实例化。每次实例化都会开辟一块新的内存。

    对象的初始化:对象的初始化是在类实例化后产生了对象、此时这个对象还不能完全能给外部调用,处在一个"中间态"。

    参考【深度解析C++之初始化列表】_new 对象有初始化列表-CSDN博客

    二、初始化列表

    初始化列表在构造函数执行之前完成成员的初始化。初始化列表里面初始化的是类对象的成员变量,不仅可以初始化const变量,也可以初始化常规变量。

    1. //v1对m1进行初始化,v1,v2对m2进行初始化,v3对m3进行初始化
    2. ClassName::ClassName():m1(v1), m2(v1,v2), m3(v3)
    3. {
    4. //
    5. }

    为什么使用初始化列表?

    1.效率

    1. class MyClass {
    2. public:
    3. int x;
    4. double y;
    5. MyClass(int a, double b) {
    6. x = a;
    7. y = b;
    8. }
    9. };

    如果我们定义了这样一段代码,那么进行对象初始化的时候就会进行如下操作:

            1)利用new关键字进行内存的分配

            2)new这个关键字会自动调用构造函数来为对象当中的字段进行初始化

    但是当我们使用初始化列表的时候

    MyClass(int a, double b) : x(a), y(b) {}

    这种方式的好处在于直接创建对象的时候就已经完成了初始化,对象创建好的一瞬间就已经完成了初始化,就不需要再调用构造函数进行逐一初始化了,这里大家可能会有一个误区认为初始化列表是构造函数的一部分,这是大错特错的!!!它们两个虽然在语法结构上定义在了一起,但是其实它们是两个独立的过程,初始化列表对对象进行初始化的时候,构造函数还没有真正地开始执行!所以不需要调用构造函数就能够为对象进行初始化了

    2.成员常量变量和引用

    对于某些情况下的成员变量,例如常量或者引用,必须使用初始化列表进行初始化,不能够在构造函数的函数体内进行赋值初始化。

    常量成员变量

    常量成员变量是在声明的时候就被赋予初始值的,并且一旦被赋值就不能够在被修改,所以自然而然地也就不能够再函数体内进行赋值运算,因为一旦进入构造函数体常量成员变量就不能够再被修改。

    1. MyClass(int a) {
    2. // 错误:常量成员变量不能在构造函数体内赋值
    3. x = a;
    4. }

    正确写法: 

    1. class Example{
    2. private:
    3. int _a;
    4. double _b;
    5. public:
    6. // 使用初始化列表初始化成员变量
    7. Example(int a, double b) : _a(a), _b(b) {
    8. // 构造函数体
    9. }
    10. };
    引用成员变量

    引用成员变量必须在构造函数的初始化列表当中进行初始化,一旦引用被初始化,它将一直引用同一个对象,无法在构造函数体内重新赋值为另一个对象,如果我们尝试在构造函数体内对引用变量进行赋值,编译器就会报错。

    1. class MyClass {
    2. public:
    3. int& y;
    4. // 错误:引用成员变量必须在初始化列表中初始化
    5. MyClass(int a) {
    6. y = a;
    7. }
    8. };

    正确写法:

    1. class Example {
    2. private:
    3. const int _constantValue;
    4. int& _referenceValue;
    5. public:
    6. // 构造函数初始化列表
    7. Example(int constantValue, int& referenceValue)
    8. : _constantValue(constantValue), _referenceValue(referenceValue) {
    9. // 构造函数体
    10. }
    11. };

    3.自定义类型,且没有默认构造函数的成员变量必须走初始化列表 

    对象成员必须使用初始化列表进行初始化,因为如果不在初始化列表当中对这个对象和进行初始化的话,那么Date类的构造函数会自动去调用_t 的默认构造函数来进行初始化,但是Time类没有默认构造函数,编译器就会报错引发未定义行为。所以初始化对象成员要么自动调用默认构造函数,如果没有默认构造函数的话,就必须使用初始化列表进行初始化

    默认构造函数是什么?C++当中的默认构造函数一共有三类:1是我们不写编译器自动为我们生成的,2是无参构造函数,3是全缺省参数的构造函数。当我们显示地定义了构造函数编译器就不会为我们生成默认构造函数了,除非我们自己写一个默认构造函数,所以这个时候对象成员初始化的时候如果要依靠编译器自动调用它的默认构造函数,他必须有默认构造函数才可以。如果没有的话那么就必须在初始化列表当中进行初始化才可以。

    1. class Time {
    2. public:
    3. int _hour;
    4. int _minute;
    5. int _second;
    6. // 构造函数
    7. Time(int hour, int minute, int second)
    8. : _hour(hour), _minute(minute), _second(second) {
    9. // 构造函数体
    10. }
    11. };
    12. class Date {
    13. private:
    14. Time _t;
    15. public:
    16. // 使用初始化列表调用 Time 类中的构造函数
    17. Date(int hour, int minute, int second)
    18. : _t(hour, minute, second) {
    19. // 构造函数体
    20. }
    21. };

    注意事项

    成员变量初始化顺序

    初始化列表中的成员变量初始化顺序与它们在类中声明的顺序有关,而不是出现在初始化列表中的顺序

    1. class B{
    2. private:
    3. int i;
    4. int j;
    5. public:
    6. B(int value):j(value),i(j){
    7. cout << "i = " << i << endl;
    8. cout << "j = " << j << endl;
    9. }
    10. };
    11. int main(){
    12. B objC(10);
    13. return 0;
    14. }

    结果如下:

    上述程序代码看起来像是要把 j 设初值为 value,再把 i 设初值为 j.问题在于,由于声明次序的原因,初始化列表中的”i (j)”其实比”j(value)”更早执行。但因为j 一开始未有初值,所以i(j)的执行结果导致无法预知其值。就输出随机值。

    改进代码:将赋值代码写在函数体中

    1. class B{
    2. private:
    3. int i;
    4. int j;
    5. public:
    6. B(int value):j(value){
    7. i = j;
    8. cout << "i = " << i << endl;
    9. cout << "j = " << j << endl;
    10. }
    11. };
    12. int main(){
    13. B objC(10);
    14. return 0;
    15. }

     

    避免使用未初始化的成员变量

    在初始化列表中确保所有成员变量都被初始化,避免使用未初始化的成员变量,尤其是对于常量和引用成员。

    常量成员变量必须在初始化列表中进行初始化

    引用成员变量

    引用成员变量必须在初始化列表中与某个对象绑定。初始化列表是C++中一个重要的概念,尤其在构造函数中的使用,它可以提高代码的效率,同时确保对象在被创建时具有正确的初始状态。

    三、成员类

    当一个类的数据成员含有一个前面已经声明的类的对象时,这个被包含的类被称作成员类,该数据成员为成员对象。(即类的成员是一个其他类的对象)

    注意:

    1. 出现成员对象时,该类的构造函数也要初始化成员对象,且必须使用初始化语法形式(在构造函数体内将 t 初始化无效)。
    2. 如果构造函数的成员初始化列表没有对成员对象初始化时,则使用成员对象的缺省构造函数。
    3. 如果成员对象没有缺省构造函数(仅有参构造函数),那么必须在类的初始化列表对成员对象进行显式的初始化。
    4. 一个含有成员对象的类实例化时要优先调用成员对象的构造函数,然后再调用该类的构造函数;析构时先调用含成员对象的类的析构函数,再调用成员对象对应类的析构函数。
    5. 如果一个类有多个成员类对象,构造函数的调用顺序是对象在类中被声明的顺序,而不是在构造函数初始化列表中的顺序。
    1. #include<iostream>
    2. using namespace std;
    3. class Time{
    4. private:
    5. int hour;
    6. int minute;
    7. int second;
    8. public:
    9. Time(int i1, int i2, int i3) :hour(i1), minute(i2), second(i3)
    10. {
    11. cout << "Time类有参构造函数" << endl;
    12. }
    13. Time() {
    14. cout << "Time类缺省构造函数" << endl;
    15. hour = minute = second = 0;
    16. }
    17. int Gethour() { return hour; }
    18. int Getminute() { return minute; }
    19. int Getsecond() { return second; }
    20. void settime(int i1, int i2, int i3) { hour = i1; minute = i2; second = i3; }
    21. void display()
    22. {
    23. cout << hour << ":" << minute << ":" << second << endl;
    24. return;
    25. }
    26. ~Time() { cout << "Time类析构函数" << endl; }
    27. };
    28. class Date{
    29. private:
    30. int year;
    31. int month;
    32. int day;
    33. Time t;
    34. public:
    35. Date() {
    36. year = month = day = 0;
    37. cout << "Date类缺省构造函数" << endl;
    38. }
    39. Date(int i1, int i2, int i3) :t({ 0, 0, 0 }), year(i1), month(i2), day(i3)
    40. {
    41. cout << "Date类有参构造函数" << endl;
    42. }
    43. void display();
    44. void settime(int i1, int i2, int i3);
    45. ~Date()
    46. {
    47. cout << "Date类析构函数" << endl;
    48. }
    49. };
    50. void Date::display(){
    51. cout << year << ":" << month << ":" << day << ":";
    52. t.display();
    53. return;
    54. }
    55. void Date::settime(int i1, int i2, int i3){
    56. t.settime(i1,i2,i3);
    57. return;
    58. }
    59. int main(){
    60. Date d;
    61. d.display();
    62. d.settime(1, 2, 3);
    63. d.display();
    64. Date d1(4, 5, 6);
    65. d1.display();
    66. return 0;
    67. }

     运行结果:

     参考c++类——成员类_c++ 成员类-CSDN博客

     

  • 相关阅读:
    分布式与微服务概念
    官方教程 Redshift 09 Camera
    微服务环境搭建
    525. 连续数组 (前缀和 + 哈希)
    kangle一键安装脚本
    java计算机毕业设计心理学网站源码+数据库+系统+lw文档+mybatis+运行部署
    VectorDrawable-pathdata
    RuoYi-Vue-Plus 高端进阶 源码分析 系列教程
    2022北京视力防控展/北京青少年眼健康展会/中国眼博会
    探究多态的原理与实现:虚函数表、动态绑定与抽象类
  • 原文地址:https://blog.csdn.net/weixin_47755728/article/details/140407098