void f( int x ) // formal argument name == “x”
{
std::cout << x << "\n"; // print the integer value associated with “x” in
} // f()’s current (local) lexical environment
这里我们定义了使用本地关联(函数本地)词法名称的代码,在本例中为x。 我们稍后调用该函数:
int airspeed_velocity_of_unladened_sparrow = 11 /* m/s */;
int number_thou_shalt_count_to = 3;
f( airspeed_velocity_of_unladened_sparrow ); // actual argument value = 11
f( number_thou_shalt_count_to ); // actual argument value = 3
f( -7 ); // actual argument value = -7
void f( int & x )
{
x += 1; // `x` is an alias for... what?
}
int num_birds_in_hand = 0;
f( num_birds_in_hand ); // f()-local `x` == `num_birds_in_hand`
std::cout << x << "\n"; // prints 1!
std::ostream & operator << ( std::ostream & outs, const my_type & value )
{
// serialize whatever my_type object may be (possibly something large
// or non-copyable) and output it to the `outs` stream.
// Once done, we return the argument stream:
return outs;
}
my_type quux;
std::cout << quux << "\n";
3条答案
按热度按时间wmvff8tz1#
我认为const变量应该初始化
它们当然是初始化的。每次调用这个函数都会为这些参数提供值,从而初始化它们。保证。每次。它们是
const
还是const
并不重要。每次调用这个函数时,它们仍然会被初始化。没有其他的选择,这就是C在基本层面上的工作方式。当它们在形参列表中定义时。
从技术上讲,这不是一个定义。这是一个声明。
您会发现,相同的C关键字往往意味着(有时略有不同,有时根本不同)不同的东西,这取决于它的上下文。
当使用
const
关键字在全局作用域中声明一个对象时,该对象必须被初始化为:如果这是一个全局变量定义,那么这是一个格式错误的定义,它将无法编译。
但是函数参数不是全局变量。
jq6vz3qz2#
这里的“const”表示函数不会修改这些值。传入的值不必是常量。
jobtbby33#
词汇环境
词法环境是一个名称/对象查找,也就是说,我可以给某个东西一个名称(和一个类型),并把它与某个对象值关联起来。
有时也可以修改变量名与对象的关联。对于普通变量,我们可以在创建变量时赋值:
或者在某个其它时间:
在C和C++中,我们可以告诉编译器,当我们使用关键字
const
时,名称对象关联不能被改变:一个值的
const
性在多大程度上是永久性的取决于这里没有讨论的各种因素,但这个想法很简单,你告诉编译器,重要的是,告诉 * 代码的用户 *,你保证不会试图改变标记为const
的东西。此外,这是一个巨大的简化,事情是如何工作的,但它是如何 * 语言 * 看待宇宙,以及 * 你,程序员 * 一般应该以及。
形式参数名·vs·实际参数值
现在我们来介绍更多的词汇,一个函数有形式参数名***(或者 * 形式参数名 *,但是在C和C++中我们使用"argument"而不是parameter),也就是说,我们告诉编译器在为函数创建局部词法环境时,我们想要使用什么 * name *。
当我们invoke**(或 * call )一个函数时,我们提供实际参数值。这些实际值是 * 重复的 *,并且 * 重复的值 * 与函数新的本地词法环境中的形式参数名相关联。
举个例子:
这里我们定义了使用本地关联(函数本地)词法名称的代码,在本例中为
x
。我们稍后调用该函数:
每次调用函数时,都会为函数创建一个新的词法环境,其中形式参数名与实际参数值的副本相关联。
一旦函数完成了它的业务,它的本地词法环境就被破坏,程序控制返回到调用函数的地方。
这种将值与名称关联(或绑定)的思想正是词法环境的意义所在,也是函数如何工作的,如果我不能在每次调用
x
时使用它的不同值来重用f()
,那么这将是非常非常没有意义的。按值调用与按引用调用
到目前为止,我们已经描述了 * 按值调用 * 语义:创建对象值的本地副本并将其绑定到本地名称。
然而,在C++中,可以创建一个 * reference *。一个reference是另一个现存对象值的别名。换句话说,我们可以在词法环境中有多个名称引用同一个对象值!
或者,换句话说,整数对象值
12
现在与 * 两个 * 名称(x
和y
)相关联,这两个名称中的任何一个都可以用来访问整数对象。reference参数做同样的事情,除了函数的本地词法环境是用调用者词法环境中的值的别名创建的!
换句话说,当我们将
f()
的本地x
绑定(或关联)到一个对象时,我们只是将它绑定到num_birds_in_hand
所绑定到的同一个对象。或者,换句话说,整数对象值
0
现在与 * 两个 * 名称(num_birds_in_hand
和x
)相关联,这两个名称中的任何一个都可以用来访问整数对象。只要
f()
的本地词法环境存在,与名称num_birds_in_hand
相关联的整数也与名称x
相关联。(And同样,当函数终止时,其词法环境被破坏,并且
num_birds_in_hand
不再具有任何别名。)而且,为了美观起见,每次调用
f()
时,我们都可以使用别名为不同对象值的x
初始化其本地词法环境。常量引用
这个引用可能会引起问题,有时我们需要某种承诺,即我的
num_birds_in_hand
***不会***被修改,即使我给出了它的别名。这就是
const
形式参数的作用,通过用const
标记形式参数,我们保证当函数被调用并且本地词法环境被创建时,它不会被用来改变实际的参数值。引用参数的用途有两个:允许一个函数修改调用者词法环境中的值,并避免复制一些昂贵的(或不可复制的)东西。例如,标准库中的
fstream
对象不能被复制。因此我们只能将它们作为引用传递。你可以在插入操作符重载中看到这一点:常量值
在您向我们展示的代码中:
将
a
和b
标记为const
实际上没有什么意义-没有人关心add()
如何处理其实际参数值的本地 * 副本 *。(有时编写函数代码的人会关心,所以他或她会用
const
标记形式参数名,但没有人关心这个函数。)(That我说,有时候人们确实关心。在示例代码中,它确实告诉调用者
a
和b
在使用它们的值之前不会有奇怪的事情发生。但我认为这只是意味着调用者对函数的内部工作方式了解太多。据我所知,当 * 调用 * 一个函数时,这个函数是如何工作的,这对我来说应该是未知的魔法。)然而,最终,按值传递的参数是否标记为
const
并不重要。时间;日期
形式参数名被 * 初始化 * 为实际参数值 * 每次调用函数时 * -在函数代码执行之前,创建一个新的词法环境,该词法环境位于函数本地,将形式参数名绑定到实际参数值。(一旦函数
return
s,它的词法环境被破坏,程序控制返回给调用者。)