12 初始化列表

1 问题引入

  • 问题:类中是否可以定义 const 成员?

  • 示例:下面的类定义是否合法?如果合法,ci 的值是什么,存储在哪里?

    • Demo

      #include <stdio.h>
      
      class Test
      {
      private:
          const int ci;
      public:
          int getCI() 
          { 
              return ci; 
          }
      };
      
      int main()
      {
          Test t;
          
          printf("t.ci = %d\n", t.getCI());
          
          return 0;
      }
      
    • 编译

      test.cpp: In fuction 'int main()':
      test.cpp:14: error: structure 't' with uninitialized const members
      
    • 说明:类中可以定义 const 成员,但通过这个类类型定义对象时,编译器会报错:会对该 const 成员进行初始化

    • 修改:利用构造函数进行 const 成员的初始化

      #include <stdio.h>
      
      class Test
      {
      private:
          const int ci;
      public:
          Test()
          {
              ci = 10;
          }
          int getCI() 
          { 
              return ci; 
          }
      };
      
      int main()
      {
          Test t;
          
          printf("t.ci = %d\n", t.getCI());
          
          return 0;
      }
      
    • 编译

      test.cpp: In constructor 'Test::Test()':
      test.cpp:8: error: uninitialized member 'Test::ci' with 'const' type 'const int'
      test.cpp:10: error: assignment of read-only data-member 'Test::ci'
      
    • 说明:类的 const 成员必须用列表初始化

2 类成员的列表初始化

  • C++ 中提供了初始化列表对成员变量进行初始化

  • 语法规则

    ClassName::ClassName(): m1(v1),m2(v1,v2),m3(v3)
    {
        //some other initialize operator
    }
    
  • 注意事项

    • 成员的初始化顺序与成员的声明顺序相同

    • 成员的初始化顺序与初始化列表中的位置无关

      • 虽然 m1 在前,但 m1 的初始化不一定在 m2m3 之前,依赖于它们的声明顺序
      ClassName::ClassName(): m1(v1),m2(v1,v2),m3(v3)
      {
          //some other initialize operator
      }
      
    • 初始化列表先于构造函数的函数体执行

      • 当构造函数的函数体执行的时候,类的对象已经构建完毕,执行构造函数的函数体只是为了初始化这个对象的状态而已
      • 列表初始化是为了初始化,是在类的对象创建之前执行的,这是初始化和赋值之间的差异
  • 示例:初始化列表的使用

    • Demo

      #include <stdio.h>
      
      class Value
      {
      private:
          int mi;
      public:
          Value(int i)
          {
              printf("i = %d\n", i);
              mi = i;
          }
          int getI()
          {
              return mi;
          }
      };
      
      class Test
      {
      private:
          Value m2;
          Value m3;
          Value m1;
      public:
          Test() : m1(1), m2(2), m3(3)   //类的类类型成员必须使用列表初始化
          {
              printf("Test::Test()\n");
          }
      };
      
      int main()
      {
          Test t;
          
          return 0;
      }
      
    • 编译运行

      i = 2
      i = 3
      i = 1
      Test::Test()
      

3 类中的 const 成员

  • 类的 const 成员会被分配空间

  • 类的 const 成员的本质是只读变量

  • 类的 const 成员只能在初始化列表中指定初始值

  • 编译器无法直接得到 类的 const 成员的初始值,因此无法进入符号表成为真正意义上的常量

  • 示例:只读成员变量

    • Demo

      #include <stdio.h>
      
      class Value
      {
      private:
          int mi;
      public:
          Value(int i)
          {
              printf("i = %d\n", i);
              mi = i;
          }
          int getI()
          {
              return mi;
          }
      };
      
      class Test
      {
      private:
          const int ci;
          Value m2;
          Value m3;
          Value m1;
      public:
          Test() : m1(1), m2(2), m3(3), ci(100)
          {
              printf("Test::Test()\n");
          }
          int getCI()
          {
              return ci;
          }
          int setCI(int v)
          {
              int* p = const_cast<int*>(&ci);
              
              *p = v;
          }
      };
      
      int main()
      {
          Test t;
          
          printf("t.ci = %d\n", t.getCI());
          
          t.setCI(10);
          
          printf("t.ci = %d\n", t.getCI());
          
          return 0;
      }
      
    • 编译运行

      i = 2
      i = 3
      i = 1
      Test::Test()
      t.ci = 100
      t.ci = 10
      
  • 初始化与赋值的不同

    • 初始化:对正在创建的对象进行初值设置
    • 赋值:对已经存在的对象进行值设置
posted @ 2020-09-22 23:38  nxgy  阅读(105)  评论(0编辑  收藏  举报