zoukankan      html  css  js  c++  java
  • 【C++】深度探索C++对象模型读书笔记--构造函数语义学(The Semantics of constructors)(四)

    成员们的初始化队伍(member Initia

    有四种情况必须使用member initialization list:

      1. 当初始化一个reference member时;

      2. 当初始化一个const member时;

      3. 当调用一个base class的constructor,而它拥有一组参数时;

      4.当调用一个member class的constructor,而它拥有一组参数时;

     

      在这四种情况下,程序可以被正确编译运行,但是效率不高。例如:

      

    1 class Word {
    2     String name;
    3     int _cnt;
    4 public:
    5     Word() {
    6         _name = 0;
    7         _cnt = 0;
    8 }

      在这里,Word constructor会产生一个临时性的String object,然后将它初始化,之后以一个assignment运算符将临时性object指定给_name,然后再摧毁那个临时性object。

      以下是constuctor可能的内部扩张结果:

      

    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;
    }

      它会扩张成这个样子:

      

    1 Word::Word(/*this pointer goes here*/)
    2 {
    3     //调用String(int)constructor
    4     _name.String::String(0);
    5     _cnt = 0;
    6 }

      对于member initialization list的每一个成员,编译器会根据member在类中声明的顺序在constructor之内安插代码,这些代码在任何explicit user code之前。

      初始化顺序和initialization list中的项目排列顺序之间的外观错乱,会导致下面意想不到的危险:

      

    class X {
        int i;
        int j;
     public:
        X(int val): j(val), i(j){}
    }

      上述代码看起来像把j设初值为val,再把i设初值为j。问题在于,由于声明顺序的缘故,initialization list中的i(j)其实比j(val)更早执行。但因为j一开始未有初值,所以i(j)的执行结果导致i无法预知其值。所以建议总是把一个member的初始化操作和另一个放在一起,放在constructor之内,像下面这样:

      

    X::X(int val) : j(val) {
        i = j;
    }

      这里还有一个有趣的问题。initialization list中的项目被安插在constructor中,会继续保持声明顺序吗?也就是,已知:

      

    X::X(int val) : j(val) {
        i = j;
    }

      上述的代码正确吗?答案是:yes。因为initialization list的项目被放在explicit user code之前。

      

      简略地说,编译器会对initialization list一一处理并可能重新排序,以反映出members的声明顺序。它会安插一些代码到constructor 体内,并置于任何explicti code之前。

  • 相关阅读:
    抽象类和接口的区别
    Overload和Override的区别
    final和finally和finalize的区别
    C#设计模式学习笔记:简单工厂模式(工厂方法模式前奏篇)
    C#设计模式学习笔记:(1)单例模式
    C#设计模式学习笔记:设计原则
    C#加密与解密(DESRSA)学习笔记
    C# IO流与文件读写学习笔记
    C#序列化与反序列化学习笔记
    C#索引器学习笔记
  • 原文地址:https://www.cnblogs.com/vincently/p/4646945.html
Copyright © 2011-2022 走看看