zoukankan      html  css  js  c++  java
  • 初始化列表的使用

    下列情况中, 为了让程序顺利编译, 必须使用 member initialization list:
    1. 初始化一个 reference member 时;
    2. 初始化一个 const member 时;
    3. 当调用一个 base class 的 constructor, 而它拥有一组参数时;
    4. 当调用一个 memeber class 的 constructor, 而它拥有一组参数时.

    考察以下代码:

    class Word
    {
        String _name;
        int    _cnt;
    public:
        //没有错误, 只是效率低
        Word()
        {
            _name = 0;    
            _cnt  = 0;
        }
    };

    这种情况下, Word constructor 会先产生一个暂时性的 String object, 然后将它初始化, 再以一个 assignment 运算符将暂时性的 object 指定给 _name, 然后再摧毁这个暂时性的 object, 以下是constructor 可能的内部扩张结果:

    //可能的结果
    Word::Word(/* this pointer goes here */)
    {
            //调用 String 的 default constructor
            _name.String::String();
    
            //产生暂时对象
            String temp = String(0);
    
            //memberwise 地拷贝 _name
            _name.String::operator=(temp);
           
            //摧毁暂时对象
            temp.String::~String();
            
            _cnt = 0;            
    }
    
    //另一种较好的方式
    Word::Word(): _name(0)
    {
            _cnt = 0;
    }
    
    //它会被扩张成这个样子
    //可能的代码
    Word::Word(/* this pointer goes here */)
    {
            //调用 String(int) constructor
            _name.String::String(0);
            _cnt = 0;
    }

    这又引起另外一个问题, 是否每个 member 都必须使用 member initialization list 来初始化呢?

    initialization list 不是一组函数, 编译器对于 initialization list , 会以适当次序在 constructor 之内安插初始化操作, 并且在任何 explicit user code 之前(例如之前 class Word 的初始化) 重点在于, 初始化的顺序是由 class 中的 members 声明的顺序决定, 不是由 initialization list 中的排列次序决定, 这就可能导致以下的问题:

    class X
    {
            int i;
            int j;
    public:
            //buggy, i(j) 会产生不确定行为
            X(int val):j(val), i(j)
            {}  
    };
    
    //较好的处理方式
    X::X(int val):j(val)
    { i = j; }

    还有一个有趣的问题, initialization list 中的项目被安插到 constructor 的函数体中, 会继续保存声明次序吗? 也就是说, 对于前一个代码, j 的初始化操作会安插在 explicit user assignment 操作 ( i = j ) 之前还是之后? 如果继续保存, 则这样操作也会导致不确定行为. 然而以上的代码是正确的, 因为 initialization list 的项目被放在 explicit user code 之前.

    另一个常见的问题是, 能否像下面那样, 调用一个 member function 以设定一个 member 的初值:

    //X::XFoo() 被调用
    X::X(int val): i(XFoo(val), j(val))
    {}

    答案是肯定的, 但是, 值得注意: 请使用 存在于 constructor 函数体内的一个 member, 而不要使用 存在于 initialization list 中的 member 设定初值. 因为你并不知道 XFoo() 对于 X object 的依赖程度有多高, 如果把 XFoo() 放在 constructor 体内, 那么对于到底是哪一个 member 在 XFoo() 执行时被设立初值这件事, 就不会导致模棱两可的情况. 

    用 member function 来初始化是合法的, 它会被编译器扩充为:

    // constructor 被扩充的结果
    X::X(/* this pointer */ int val)
    {
            i = this->XFoo(val);
            j = i;
    }

    那么如果一个 derived class member function 被调用, 其返回值被当作 base class constructor 的一个参数, 将会如何:

    class FooBar: public X
    {
        int _fval;
    public:
        int fval(){return _fval;}
        FooBar(int val): _fval(val), X(fval())    //使 fval() 作为 base class constructor 的参数
        {}
        ...
    };
    
    //这是个好主意吗?
    //这是可能的扩张结果
    FooBar::Foobar(/* this pointer goes here*/)
    {
        //编译器会把 initialization list 的代码扩展到 user code 的 前面
        X::X(this, this->fval());    //wtf, 导致不明确行为
        _fval = val;
    }
  • 相关阅读:
    cocos2d-x ios 设置横屏/竖屏(全)
    决策树之ID3算法实现(python)
    基于Spring开发的DUBBO服务接口测试
    Mac电脑下配置maven环境变量
    Mac Eclipse+Maven+TestNg+ReportNg 生成测试报告
    TestNG+Maven+IDEA环境搭建
    115个Java面试题和答案——终极列表(上)
    115个Java面试题和答案——终极列表(下)
    阿里巴巴常考面试题及汇总答案
    阿里面试回来,想和Java程序员谈一谈
  • 原文地址:https://www.cnblogs.com/wuOverflow/p/4101494.html
Copyright © 2011-2022 走看看