C++11 {} 初始化

  1. 简介

    • 说明

      • 主要内容是介绍{},即braces花括号在C++11中的作用。

    • 作用

      • 默认构造和默认初始化.
      • 值列表初始化。{}表示无参默认构造.
    • 默认值和随机

      #include <iostream>
      
      int main() {
         int a;
         int b{};
         std::cout << a << std::endl;
         std::cout << b << std::endl;
         return 0;
      }
      
      • 随机值和默认值.

      16
      0
      [Finished in 432ms]
      
    • 结构体

      #include <iostream>
      
      struct T {
         char a;
         char b;
         char c;
         char d;
      };
      
      int main() {
         T a;
         T b{};
         std::cout << std::hex << *(int*)&a << std::endl;
         std::cout << std::hex << *(int*)&b << std::endl;
         return 0;
      }
      
      • 输出都为0
      0
      0
      [Finished in 436ms]
      
      #include <iostream>
      
      typedef char (*T)[4];
      
      int main() {
         T a;
         T b{};
         std::cout << std::hex << *(int*)&a << std::endl;
         std::cout << std::hex << *(int*)&b << std::endl;
         return 0;
      }
      
      • 输出
      10
      0
      [Finished in 429ms]
      
      • 随机值和默认值0.
    • 重载

      #include <iostream>
      #include <vector>
      #include <initializer_list>
      
      struct T {
         T(){
             std::cout << "default" << std::endl;
         }
         T(std::initializer_list<int> initial) {
             std::cout << "initializer_list" << std::endl;
             std::vector<int> temp{initial};
         }
      };
      
      int main() {
         T a;
         T b{};
         T c{1,2,3};
         return 0;
      }
      
      • 输出

      default
      default
      initializer_list
      [Finished in 469ms]
      
    • 匹配规则

      • 优先匹配std::initializer_list构造,无参的({})才可以.

      • 无法构造initializer_list则参数拆分,匹配成员构造.

      • 对成员变量进行构造.

    • 成员变量构造

      #include <iostream>
      
      class T {
      public:
         char s[4];
      };
      
      int main() {
         T a{1,2,3,4};
         std::cout << std::hex << *(int*)&a << std::endl;
         return 0;
      }
      
      4030201
      [Finished in 432ms]
      
    • 数组和成员

      #include <iostream>
      
      class T {
      public:
         char a:4;
         char b:4;
         char s[3];
      };
      
      int main() {
         T a{1,2,3,4};
         T b{1,2,3,4,5};
         std::cout << std::hex << *(int*)&a << std::endl;
         std::cout << std::hex << *(int*)&b << std::endl;
         return 0;
      }
      
      40321
      5040321
      [Finished in 432ms]
      
  2. 初始化

    • 各种初始化

      int main() {
         int a(0);
         int b = 0;
         int c{ 0 };
         int d = { 0 };
      }
      
      • 效果都一样,都是初始化变量.
    • 对等

      int main() {
         int b = { 0 };
         int c{ 0 };
      }
      
      • 两种相等,后面介绍都统一用不包括=的.
  3. 赋值和初始化

    • 初始化和赋值

      #include <iostream>
      
      class T {
      public:
         T(char a) { std::cout << "int" << std::endl; }
         explicit T(T*) { std::cout << "float" << std::endl; }
         T(const T&) { std::cout << "cons" << std::endl; }
         void operator=(const T&) {
             std::cout << "assign" << std::endl;
         }
      };
      
      int main() {
         T a = 1;
         //T b = nullptr;
         T c(nullptr);
         T d = a;
         d = a;
      }
      
      • 执行结果是
      int
      float
      cons
      assign
      
      D:\codes\vs\test\test\x64\Debug\test.exe (进程 9996)已退出,代码为 0。
      要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
      按任意键关闭此窗口. . .
      
      • 创建时隐式转换为对应的构造函数的入参.explicit,不允许隐式转换.
      • nullptr匹配了T*,注释掉的代码因为构造函数声明为explicit所以报错.
      • 两个T d=a也被隐式的切换为调用拷贝构造,而下面的是赋值,则调用赋值运算函数.
    • 小结

      • 声明时赋值是构造,其他则赋值.

  4. {}

    • 隐式调用拷贝构造

      #include <iostream>
      
      class T {
      public:
         T(char a) { std::cout << "int" << std::endl; }
         explicit T(T*) { std::cout << "float" << std::endl; }
         T(const T&) { std::cout << "cons" << std::endl; }
         void operator=(const T&) {
             std::cout << "assign" << std::endl;
         }
      };
      
      int main() {
         T a{ 1 };
         T b{ nullptr };
         T c{(nullptr)};
         T d{ a };
         d = { a };
         //d = { 1, a };
         d = (a);
         d = (1, a);
      }
      
      • 赋值初始化和构造初始化的差异,调用的函数不同.
      int
      float
      float
      cons
      assign
      assign
      assign
      
      D:\codes\vs\test\test\x64\Debug\test.exe (进程 9400)已退出,代码为 0。
      要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
      按任意键关闭此窗口. .
      
      • 也会隐式切换.将{a}转化为const T&,在多参数下不容易出错.
      • 可以很轻松的区分初始化和赋值的区别. 编译阶段就会报错.
  5. 出错

    • 函数还是构造

      int main() {
         int a();
         a = 2;
         return 0;
      }
      
      • 无参就是函数声明.

    • 窄化

      int main() {
         int a{1.0};
         return 0;
      }
      
      • 编译报错,因为会窄化,即double->int丢失数据.

    • 窄化概念

      • 基本类型之间,赋值导致了数据可能丢失.
    • 窄化二

      int main() {
         char a{1l};
         char b{127l};
         char c{128l};
         return 0;
      }
      
      • 这里前两个都不会,但是128超过了signed char的存储范围.

      • 上面的浮点不能往非浮点类型转换.

  6. 总结

    • 匹配优先级:initializer_list,构造,成员.

    • 作用: 统一初始化方式,适用性广.

    • 注意: 默认初始化的行为差异,auto的影响,空initializer_list:({}).

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值