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