• 构造函数语义学之程序转化语义学(1)


    大家知道初始化与赋值是有区别的,那么有哪几种初始化的方式呢?有以下三种情况://这句话可能有问题,回头修改!

      (1).明确的初始化操作(Explicit Initialization)

      (2).参数的初始化(Argument Initialization)

      (3).返回值的初始化(Explicit Initialization)

      先来看(1)---明确的初始化操作,这种比较直觉,大家一看就知道是初始化!请看如下代码:

    X x0;
    
    void foo_bar()
    {
        X x( x0 );  //定义了 x1
        X x = x0;  //定义了 x2
        X x = X( x0 ); //定义了 x3
        //...
    }

      那么编译器会给此段代码如何转化呢?分为两个阶段:

      (a). 重写每一个定义,其中的初始化操作会被剥除。

      (b).class 的 copy constructor 调用操作会被安插进去。

      那么转化后的代码就会变成像下面这个样子:

    //可能的程序转化
    //C++weidamai 
    
    void foo_bar()
    {
        X x1;     //定义被重写,初始化被剥除
        X x2;     //定义被重写,初始化被剥除
        X x3;     //定义被重写,初始化被剥除     
    
        // 编译器安插 X copy construction 的调用操作
        x1.X::x( x0 );    
        x2.X::x( x0 );  
        x3.X::x( x0 );  
    } 

      在看(2)---参数的初始化( Argument Initialization),这种初始化挺常见,只是大家不容易发现。请看如下代码:

        void foo( X x0 );   //若已知这个函数

        //下面这样的调用方式

        X xx;

        foo( xx );

      这种代码可能看出有初始化,但其实发生了 X arg = xx; arg 代表 foo 的参数, 而 arg 代表真真的参数值。也就是初始化了一个临时变量!伪代码类似如下:

           // C++ 伪代码

         // 编译器产生出来的暂时对象

        X __temp0;

        // 编译器对copy constructor 的调用

        __temp0.X::X( xx );

        // 重新该写函数调用操作,以便使用上述的暂时对象

        foo( __temp0  );

      大家看到 foo( __ temp0 );的时候肯定回想这不又还原了吗,不和 foo( xx ) ;一样了嘛?确实如此,但是编译器把 foo() 函数的声明也换了,改成了 void foo( X& x0) !!!其中,class X 中肯定有析构函数,他会在 foo() 函数完成之后被调用,对付那个暂时性的 object (上面的 __temp0 )。

      最后看(3)---返回值的初始化( Return Value Initialization),这种也比较容易发现,看如下代码:

        X bar()

        {

           X xx;

           // operation

           //return xx;

        }

        X =  bar();

      你可能会问 bar() 的返回值如何从局部对象 xx 中拷贝过来?有的编译器采用一个双阶段转化:

      a. 首先加上一个额外的参数,类型时 class object 的一个 reference。这个参数用来防止被“拷贝构建( copy constructed )” 而得的返回值。

      b. 在 return 指令之前安插一个 copy constructor 调用操作,一遍将欲传回的 object 的内容当做上述新增参数的初值。

      那么以上的代码就可能被转化下面这个样子:

        //函数转化以反映出 copy constructor 的应用

        // C++ 伪码

        void bar( X & __result )

        {

          X xx;

          //编译器产生的 default constructor 调用操作 

          xx.X::X();

          //处理 xx

          //编译器所产生的 copy constructor 调用操作

          __result.X::X( xx );

          return ;

        }

        接下来编译器必须转化么一个 bar() 调用操作,以反映其新的定义。

        X xx = bar();

        将被转为如下两步:

        X xx;

        bar( xx );

        而 bar().fun();类似的则被翻译为:

        X __temp0; //编译器会给你创建一个临时变量,then

        (bar ( __temp0 ), __temp0).fun();

        同样道理,如果声明了指针函数并用来指向 bar() ,那么函数指针也会被重新定义!

      编译器只是简单的做如上的转化吗?他们有时还会做更多的优化转化,且看接下来的 构造函数语义学之程序转化语义学(2)!

  • 相关阅读:
    SuperSubScriptHelper——Unicode上下标辅助类
    IniHelper——INI操作辅助类
    跨站脚本 XSS<一:介绍>
    Vim入门教程
    Linux学习进阶路线图
    web过滤器中获取请求的参数(content-type:multipart/form-data)
    代码注释模板
    log4j:WARN No appenders could be found for logger
    mysql exists 和 in的效率比较
    JSP的隐式对象
  • 原文地址:https://www.cnblogs.com/zhuwbox/p/3420503.html
Copyright © 2020-2023  润新知