zoukankan      html  css  js  c++  java
  • 第8课 列表初始化(3)_防止类型收窄、explicit关键字

    1. 防止类型收窄

    (1)类型收窄:指的是导致数据内容发生变化或者精度丢失隐式类型转换

    (2)类型收窄的几种情况

      ①从浮点数隐式转换为整型数,如int i=2.2;

      ②从高精度浮点数隐式转换为低精度浮点数。如从long double转double或float。

      ③从整型数隐式转换为浮点数,并且超出浮点数的表示范围,如float=(unsigned long Long)-1,注意这表示将-1先强制转换为unsigned long long,再隐式转换为float。

      ④从整型数隐式转换为长度较短的整型数,并且超出其表示范围。如char x=65536。

    (3)在C++98/03中,类型收窄编译器不会报错,而C++11中可以通过列表初始化来检查及防止类型收窄

    【编程实验】防止类型收窄

    #include <iostream>
    #include <vector>
    using namespace  std;
    
    int main()
    {
        int x1(5.3);   //ok,x1=5
        int x2 = 5.3;  //ok,x2=5
        int x3 {5.3};  //error:narrowing,gcc给的是warning
        int x4 = {5.3};//同上
        char c1{7};    //ok
        char c2{99999};//error:narrowing,gcc给的是warning
        std::vector<int> v1{1,2,3,4,5}; //ok
        std::vector<int> v2{1,2,3,4,5.6}; //error:narrowing,gcc给的是warning
        
        float fa = 1e40;  //ok,double->float
        float fb = {1e40};//error,double->float,超过float能表示的范围
        float fc = (unsigned long long)-1; //将-1(0xFFFFFFFF)强转,再隐式转成float
        float fd = {(unsigned long long)-1}; //error
        float fe = (unsigned long long)1; //将1强转,再隐式转成float
        float ff = {(unsigned long long)1}; //ok
        
        const int x = 1024, y = 1; //注意x,y被const修饰
        char c = x;  //ok
        char d = {x};//error
        char e = y;  //ok
        char f = {y};//ok。如果y为int型,则该行会出错。但由于加了const并且值为1。编译器
                     //认为这样的转换是安全的。
        
        
        return 0;
    }
    /*
    *******************gcc上的测试结果*********************
    e:StudyC++118>g++ -std=c++11 test1.cpp
    test1.cpp: In function 'int main()':
    test1.cpp:9:13: error: narrowing conversion of '5.2999999999999998e+0' from 'double' to 'int' inside { } [-Wnarrowing]
    test1.cpp:10:15: error: narrowing conversion of '5.2999999999999998e+0' from 'double' to 'int' inside { } [-Wnarrowing]
    test1.cpp:12:15: error: narrowing conversion of '99999' from 'int' to 'char' inside { } [-Wnarrowing]
    test1.cpp:14:33: error: narrowing conversion of '5.5999999999999996e+0' from 'double' to 'int' inside { } [-Wnarrowing]
    test1.cpp:17:18: error: narrowing conversion of '1.0e+40' from 'double' to 'float' inside { } [-Wnarrowing]
    test1.cpp:19:36: error: narrowing conversion of '18446744073709551615ull' from 'long long unsigned int' to 'float' inside { } [-Wnarrowing]
    test1.cpp:24:11: warning: overflow in implicit constant conversion [-Woverflow]
    test1.cpp:25:13: error: narrowing conversion of '1024' from 'int' to 'char' inside { } [-Wnarrowing]
      
    *******************vc2015上的测试结果*********************
    test1.cpp(9): error C2397: 从“double”转换到“int”需要收缩转换
    test1.cpp(10): error C2397: 从“double”转换到“int”需要收缩转换
    test1.cpp(12): error C2397: 从“int”转换到“char”需要收缩转换
    test1.cpp(14): error C2398: 元素“5”: 从“double”转换到“int”需要收缩转换
    test1.cpp(17): error C2397: 从“double”转换到“float”需要收缩转换
    test1.cpp(19): error C2397: 从“unsigned __int64”转换到“float”需要收缩转换
    test1.cpp(25): error C2397: 从“const int”转换到“char”需要收缩转换
    */

    2. explicit关键字

    (1)explicit用于阻止编译器的隐式转换,一般用于修饰构造函数

    (2)C++98/03由于不能使用{}列表初始化,即隐式转换只发生在调用带一个参数的构造函数中。但C++11允许用{}列表初始化对象,这可能会隐式调用带多个参数的构造函数

    (3)C++11中,explicit可用于修饰带多个参数的构造函数以防止隐式转换。(注意C++98/03中explicit被用于修饰只带一个参数的构造函数,如果修饰带多个参数的构造函数则无效)

    【编程实验】explicit修饰带多参的构造函数

      1 #include <iostream>
      2 using namespace std;
      3 
      4 class Test
      5 {
      6 public:
      7     Test(int a, int b)
      8     {
      9         cout <<"Test(int a, int b)" << endl;
     10     }
     11     
     12     Test(initializer_list<int>)
     13     {
     14         cout <<"Test(initializer_list<int>)" << endl;
     15     }
     16     
     17     explicit Test(int a, int b, int c)
     18     {
     19         cout <<"explicit Test(int a, int b, int c)" << endl;
     20     }
     21 };
     22 
     23 void func(const Test& t)
     24 {
     25     
     26 }
     27 
     28 struct Complex
     29 {
     30     int real, imag;
     31     
     32     //explicit 
     33     Complex(int re, int im = 0):real(re), imag(im){}
     34     
     35     Complex operator+(const Complex& x)
     36     {
     37         return Complex((real+x.real),(imag+x.imag));
     38     }
     39 };
     40 
     41 int main()
     42 {
     43     Complex c1(12, 5);
     44     Complex c2 = c1 + 5;//会试图将5转换为Complex类型,所以会隐式调用构造
     45                         //函数。为了阻止这种行为,可以在构造函数前加explicit
     46     
     47     //1.由于Test带有一个initializer_list参数的构造函数,因此,下列
     48     //用{}初始化的对象都会直接调用该构造函数。
     49     //2.如果注释掉上述构造函数,则编译器会将{...}分解并传给相应的
     50     //构造函数,如果找不到相应的带多参的构造函数,则直接报错。
     51     Test t1(77, 5);       //Test(int a, int b)
     52     Test t2{77, 5};       //Test(initializer_list<int>)
     53     Test t3{77, 5, 42};   //Test(initializer_list<int>)
     54     Test t4 = {77, 5};    //Test(initializer_list<int>)
     55     Test t5 = {77, 5, 42};//Test(initializer_list<int>)
     56     Test t6(77, 5, 42);   //ok,显式调用explicit Test(int a, int b, int c)
     57     
     58     func({47, 11});           //Test(initializer_list<int>)
     59     func({47, 11, 3});        //Test(initializer_list<int>)
     60     func(Test{47, 11});       //Test(initializer_list<int>)
     61     func(Test{47, 11, 3});    //Test(initializer_list<int>)
     62     
     63     Test t11{77, 5, 42, 500};   //Test(initializer_list<int>)
     64     Test t12 = {77, 5, 42, 500};//Test(initializer_list<int>)
     65     Test t13 {10};  //Test(initializer_list<int>)
     66     
     67     return 0;
     68 }
     69 /*测试结果:
     70 **************************不注释Test中带有一个initializer_list参数的构造函数***************************
     71 e:StudyC++118>g++ -std=c++11 test2.cpp
     72 e:StudyC++118>a.exe
     73 Test(int a, int b)
     74 Test(initializer_list<int>)
     75 Test(initializer_list<int>)
     76 Test(initializer_list<int>)
     77 Test(initializer_list<int>)
     78 explicit Test(int a, int b, int c)
     79 Test(initializer_list<int>)
     80 Test(initializer_list<int>)
     81 Test(initializer_list<int>)
     82 Test(initializer_list<int>)
     83 Test(initializer_list<int>)
     84 Test(initializer_list<int>)
     85 Test(initializer_list<int>)
     86 
     87 **************************不注释Test中带有一个initializer_list参数的构造函数***************************
     88 e:StudyC++118>g++ -std=c++11 test2.cpp -fno-elide-constructors
     89 test2.cpp: In function 'int main()':
     90 test2.cpp:55:22: error: converting to 'Test' from initializer list would use explicit constructor 'Test::Test(int, int, int)'
     91   Test t5 = {77, 5, 42};
     92 
     93 test2.cpp:59:18: error: converting to 'const Test' from initializer list would use explicit constructor 'Test::Test(int, int, int)'
     94   func({47, 11, 3});  
     95 
     96 test2.cpp:63:25: error: no matching function for call to 'Test::Test(<brace-enclosed initializer list>)'
     97   Test t11{77, 5, 42, 500}; 
     98 
     99 test2.cpp:64:28: error: could not convert '{77, 5, 42, 500}' from '<brace-enclosed initializer list>' to 'Test'
    100   Test t12 = {77, 5, 42, 500};
    101 
    102 test2.cpp:65:14: error: no matching function for call to 'Test::Test(<brace-enclosed initializer list>)'
    103   Test t13 {10};
    104 */
  • 相关阅读:
    spring 中常用的配置项
    @Value 和 @ConfigurationProperties 获取值的比较
    js 数组循环删除元素或对象
    STS 控制台 中文乱码(maven 中文乱码)
    STS application.properties 中文乱码
    [翻译] USING GIT IN XCODE [2] 在XCODE中使用GIT[2]
    [翻译] USING GIT IN XCODE [1] 在XCODE中使用GIT[1]
    [翻译] GTAppMenuController
    [翻译] ATTutorialController
    [翻译] ZCSHoldProgress
  • 原文地址:https://www.cnblogs.com/5iedu/p/7628814.html
Copyright © 2011-2022 走看看