美文网首页
C++11标准常用特性---统一初始化

C++11标准常用特性---统一初始化

作者: Sky_Mao | 来源:发表于2020-01-23 16:18 被阅读0次

    1、在给结构体赋值的时候,可以使用一对大括号来进行赋值,赋值过程中会按照结构体成员顺序来进行赋值;

    struct initTest
    {
        int nNum;
        string str;
    };
    
    initTest o = { 1, "初始化" }; //第一种初始化方式
    initTest o2{ 1, "初始化" };   //第二种初始化方式
    

    初始化的类型是否按照顺序指定的呢?
    传入一个错误的类型试试,看下编译器会提示什么。

    错误提示.png
    从编译器的错误提示中可以看到,第一个参数类型已经被确定为int类型。

    2、初始化列表初始化类

    class initClass
    {
    public:
        initClass(int nC, string str) {};
    };
    
    initClass o = { 2, "初始化" }; //第一种初始化方式
    initClass o2{ 1, "初始化" };   //第二种初始化方式
    

    3、初始化同类型不定个数参数

    C++11把初始化列表的概念绑到一个叫做std::initializer_list的模板上,这允许构造函数或其他函数将初始化列表做为参数.例如:

    template<class T>
    class initClass
    {
    public:
        initClass(initializer_list<T> initList) {};
    };
    
    initializer_list<int> oList{ 1, 2, 3, 4, 5, 6, 7 };
    initClass<int> o{ oList };
    
    initializer_list<double> oListd{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 };
    initClass<double> oD{ oListd };
    

    这个构造函数是一种特殊的构造函数,叫做初始化列表构造函数(initializer-list-constructor)
    \color{#FF3030}{类型std::initializer_list<>是个第一级的C++11标准程序库类型,但是,它们只能由C++11通过\{\}}
    \color{#FF3030}{这个列表一经构造便可复制,虽然这只是copy-by-reference。初始化列表是常数;}
    \color{#FF3030}{一旦被创建,其成员均不能被改变,成员中的数据也不能够被改变。}

    函数统一类型入参也可以使用:

    void FunctionName(initializer_list<float> list);  
    FunctionName({1.0f, -3.45f, -0.4f}); 
    

    4、标准容器的统一初始化

    C++11之前初始化一个vector,需要调用多次push_back函数进行初始化。

    vector<double> oDList;
    oDList.push_back(1.0);
    oDList.push_back(2.0);
    

    C++11可以这么实现:

    vector<double> oDList{ 1.0, 2.0 };
    vector<double> oDList = { 1.0, 2.0 };
    vector<double> oDList({ 1.0, 2.0 });
    

    \color{#FF3030}{注意:这种方式初始化不同与add,所以循环内初始化还是需要使用push_back函数的。}

    5、非静态类成员赋值

    C++11之前只有静态成员在声明的时候可以赋初值。C++11让非静态成员也可以在声明的时候赋值。

    class initClass
    {
    public:
        initClass() {};
    private:
        int m_nC = 0;
        string m_str = "";
    };
    

    如果初始化列表对类initClass的两个赋过初值的成员变量进行了另外的初始化,那么赋值的内容会被覆盖。
    小测试一下:
    修改代码如下:

    class initClass
    {
    public:
        initClass(const int nC, const string str) : m_nC(nC), m_str(str) {};
    
        int getNc() { return m_nC; };
        string getStr() { return m_str; };
    private:
        int m_nC = 0;
        string m_str = "";
    };
    
    initClass test1{ 10, "test" };
    cout << "initClass::m_nC:\t" << test1.getNc() << endl;
    cout << "initClass::m_str:\t" << test1.getStr() << endl;
    

    测试结果:


    测试结果.png

    6、对象构造的改进

    C++11以前类的构造函数不允许调用该类的其它构造函数;每个构造函数都必须自己或者调用一个公共的成员函数来构造类的全部成员.例如:

    class SomeType1
    {
    public:
        SomeType1(int new_number) : number(new_number) {}
        SomeType1() : number(42) {}
    private:
        int number;
    };
    
    class SomeType2 
    {
    public:
        SomeType2(int new_number) { init(new_number); } //必须调用一个公共初始化函数进行初始化成员
        SomeType2() { init(42); }
    private:
        void init(int new_number) { number = new_number; }
    
    private:
        int number;
    };
    

    而且,基类的构造函数不能直接暴露给派生类;每个派生类必须实现自己的构造函数哪怕基类的构造函数已经够用了.非静态数据成员不能在声明的地方初始化.它们只能在构造函数中初始化.
    C++11为这些问题提供了解决方案.C++11允许构造函数调用另一个构造函数(叫做委托构造).这允许构造函数利用其它构造函数的行为而只需增加少量的代码.C#,java和D语言都提供了这种功能. C++的语法如下:

    class SomeType1
    {
    public:
        SomeType1(int new_number) : number(new_number) {}
        SomeType1() : SomeType1(42) {}
    private:
        int number;
    };
    

    注意:这个例子可以通过给new_number设定一个默认参数来达到相同的效果.但是,这种新语法可以让这个默认值在实现中来设置而不是在接口中设置.这带来的一个好处就是,对库代码的维护者而言,在接口中(头文件中)声明默认值,这个默认值被嵌入到了调用端;要改变这个默认值的话,调用端的代码都需要重新编译.但委托构造可以在实现中(CPP文件中)来改变这个默认值, 这样调用端的代码就不需要重新编译,只用重新编译这个库就可以了.

    相关文章

      网友评论

          本文标题:C++11标准常用特性---统一初始化

          本文链接:https://www.haomeiwen.com/subject/lxunzctx.html