繁体   English   中英

为什么const参数定义的时候不需要初始化?

[英]Why don't const parameters need to be initialized when they're defined?

#include<iostream>
using namespace std;
int add(const int a, const int b)
{
    return a+b;
}

为什么上面的代码是正确的? 我认为 const 变量应该在形式参数列表中定义时进行初始化。

我认为应该初始化 const 变量

他们肯定被初始化了。 每次调用此 function 都会为这些参数提供值,这些值会初始化它们。 保证。 每次。 它们是否为const并不重要。 每次调用此 function 时,它们仍会被初始化。 没有其他选择,这就是 C++ 在基本层面上的工作方式。

当它们在形式参数列表中定义时。

从技术上讲,这不是定义。 这是一个宣言。

您会发现,相同的 C++ 关键字通常表示(有时略有不同,有时则完全不同),这取决于其上下文。

当使用const关键字在全局 scope 中声明一个 object 时,必须将 object 初始化为:

const int a;

如果这是一个全局变量定义,那么它的格式是错误的,它不会编译。

但是function参数不是全局变量。

'const' 这里是 promise function 不会修改这些值。 传入的值不必是常量。

词法环境

词法环境是名称 ⟶ object 查找。 也就是说,我可以给一些东西一个名字(和一个类型)并将它与一些 object 值相关联。

int x = -7;           /*
↑   ↑    ↑
↑   ↑    object value
↑   name
type                  */

std::string s = "Hello world!";
//          ↑      ↑
//          ↑      object value
//          name

也有名字⟶object关联可以修改的时候。 对于普通变量,我们可以在创建时赋值:

int x = -7;         // associated with a value at creation

或者在其他时间:

string name;        // associated with a default value
name = "Bon-Jovi";  // associated with a new value

在 C 和 C++ 中,当我们使用关键字const时,我们可以告诉编译器名称 ⟶ object 关联不能更改:

const x = -7;
x = 42;             // compile error: cannot change x’s value

一个值的const永久性的程度取决于这里没有讨论的各种因素,但这个想法很简单,就是你告诉编译器,重要的是,你的代码的用户,你保证不会尝试改变标记为const的东西.

此外,这是对底层工作方式的极大简化,但它是语言看待宇宙的方式,也是程序员通常应该如何看待的方式。


正式参数名称•vs• 实际参数值

现在更多的词汇。 一个function正式的参数名称(或formal parameter names ,但在 C 和 C++ 中我们使用“argument”这个词而不是参数),也就是说,我们告诉编译器我们想在本地词法环境中使用什么名称是为 function 创建的。

当我们调用(或调用)function 时,我们提供实际参数值 这些实际值是重复的,重复的值与函数新的本地词法环境中的正式参数名称相关联。

一个例子:

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

我们稍后调用 function:

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

每次调用 function 时,都会为 function 创建一个新的词法环境,其中形式参数名称与实际参数值的副本相关联。

一旦 function 完成其业务,其本地词法环境将被破坏,程序控制将返回到调用 function 的位置。

这种将值与名称相关联(或绑定)的想法正是词法环境的意义所在,以及函数的工作方式。 如果我不能在每次调用它时用不同的x值重新使用f() ,那将是真的、真的毫无意义。


按值调用 •与• 按引用调用

到目前为止,我们已经描述了按值调用语义:创建对象值的本地副本并将其绑定到本地名称。

然而,在 C++ 中,可以创建一个引用 引用是另一个现存 object 值的别名。 换句话说,我们的词法环境中可以有多个名称引用相同的 object 值!

int   x = 12;  // x ⟶ integer 12
int & y = x;   // y ⟶ that ↑ same integer
y = 93;        // same as: x = 93

或者,换句话说,integer object 值12现在与两个名称( xy )相关联,其中任何一个都可用于访问 integer object。

引用参数做同样的事情,除了函数的局部词法环境是用调用者词法环境中的值的别名创建的!

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!

换句话说,当我们将f()的局部x绑定(或关联)到 object 时,我们只需将它绑定到num_birds_in_hand绑定到的同一个 object。

或者,换句话说,integer object 值0现在与两个名称( num_birds_in_handx )相关联,其中任何一个都可用于访问 integer object。

只要f()的本地词法环境存在,与名称num_birds_in_hand也与名称x关联。

(同样,当 function 终止时,它的词法环境被破坏, num_birds_in_hand不再有任何别名。)

而且,为了这一切的美妙,每次我们调用f()时,我们都可以使用x别名 object 值来初始化它的局部词法环境。

int I_am_different = 37;
f( I_am_different );
std::cout << I_am_different << "\n";  // prints “38”

常量引用

这个引用的东西可能会导致问题。 有时我们想要某种 promise,我的num_birds_in_hand不会被修改,即使我给它一个别名。

这就是const形式论证的用途。 通过用const标记正式参数,我们 promise 当调用 function 并创建本地词法环境时,它不会用于更改实际参数值。

void g( const int & x )  // const == promise not to modify x’s object value
{
  x += 1;                // compile error: cannot change x’s value
}

引用参数的目的是双重的:允许 function 修改调用者词法环境中的值,并避免复制昂贵的(或不可复制的)东西。 例如,无法复制标准库中的fstream对象。 因此我们只能将它们作为参考传递。 您可以通过插入运算符重载看到这一点:

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

常量值

对于您向我们展示的代码:

int add( const int a, const int b )

ab标记为const确实没有多大意义——没有人关心add()对其实际参数值的本地副本做了什么。

(有时编写函数代码的人很关心,所以他或她会用const标记正式参数名称。但是没有人使用function 关心。)

(也就是说,有时人们确实关心。在示例代码中,它确实告诉调用者ab在使用它们的值之前不会对它们做任何奇怪的事情。但我认为这只是意味着调用者也知道很多关于函数的内部工作。据我所知,当调用function 时,function 是如何工作的对我来说应该是未知的魔法。)

然而,最终,值传递 arguments 是否标记为const并不重要。


tl;博士

每次调用 function 时,都会使用实际参数值初始化形式参数名称——在执行函数代码之前,创建一个新的局部于 function 的词法环境,将形式参数名称绑定到实际参数值。 (一旦 function return s,它的词法环境就被破坏,程序控制权返回给调用者。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM