c++ 为什么const参数在定义时不需要初始化?

pod7payv  于 2023-01-18  发布在  其他
关注(0)|答案(3)|浏览(206)
#include<iostream>
using namespace std;
int add(const int a, const int b)
{
    return a+b;
}

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

wmvff8tz

wmvff8tz1#

我认为const变量应该初始化
它们当然是初始化的。每次调用这个函数都会为这些参数提供值,从而初始化它们。保证。每次。它们是const还是const并不重要。每次调用这个函数时,它们仍然会被初始化。没有其他的选择,这就是C在基本层面上的工作方式。
当它们在形参列表中定义时。
从技术上讲,这不是一个定义。这是一个声明。
您会发现,相同的C
关键字往往意味着(有时略有不同,有时根本不同)不同的东西,这取决于它的上下文。
当使用const关键字在全局作用域中声明一个对象时,该对象必须被初始化为:

const int a;

如果这是一个全局变量定义,那么这是一个格式错误的定义,它将无法编译。
但是函数参数不是全局变量。

jq6vz3qz

jq6vz3qz2#

这里的“const”表示函数不会修改这些值。传入的值不必是常量。

jobtbby3

jobtbby33#

词汇环境

词法环境是一个名称/对象查找,也就是说,我可以给某个东西一个名称(和一个类型),并把它与某个对象值关联起来。

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

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

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

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时,名称对象关联不能被改变:

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

一个值的const性在多大程度上是永久性的取决于这里没有讨论的各种因素,但这个想法很简单,你告诉编译器,重要的是,告诉 * 代码的用户 *,你保证不会试图改变标记为const的东西。
此外,这是一个巨大的简化,事情是如何工作的,但它是如何 * 语言 * 看待宇宙,以及 * 你,程序员 * 一般应该以及。

形式参数名·vs·实际参数值

现在我们来介绍更多的词汇,一个函数形式参数名***(或者 * 形式参数名 *,但是在C和C++中我们使用"argument"而不是parameter),也就是说,我们告诉编译器在为函数创建局部词法环境时,我们想要使用什么 * name *。
当我们
invoke**(或 * call )一个函数时,我们提供实际参数值
。这些实际值是 * 重复的 *,并且 * 重复的值 * 与函数新的本地词法环境中的形式参数名相关联。
举个例子:

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

每次调用函数时,都会为函数创建一个新的词法环境,其中形式参数名与实际参数值的副本相关联。
一旦函数完成了它的业务,它的本地词法环境就被破坏,程序控制返回到调用函数的地方。
这种将值与名称关联(或绑定)的思想正是词法环境的意义所在,也是函数如何工作的,如果我不能在每次调用x时使用它的不同值来重用f(),那么这将是非常非常没有意义的。

按值调用与按引用调用

到目前为止,我们已经描述了 * 按值调用 * 语义:创建对象值的本地副本并将其绑定到本地名称。
然而,在C++中,可以创建一个 * reference *。一个reference是另一个现存对象值的别名。换句话说,我们可以在词法环境中有多个名称引用同一个对象值!

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

或者,换句话说,整数对象值12现在与 * 两个 * 名称(xy)相关联,这两个名称中的任何一个都可以用来访问整数对象。
reference参数做同样的事情,除了函数的本地词法环境是用调用者词法环境中的值的别名创建的!

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绑定(或关联)到一个对象时,我们只是将它绑定到num_birds_in_hand所绑定到的同一个对象。
或者,换句话说,整数对象值0现在与 * 两个 * 名称(num_birds_in_handx)相关联,这两个名称中的任何一个都可以用来访问整数对象。
只要f()的本地词法环境存在,与名称num_birds_in_hand相关联的整数也与名称x相关联。
(And同样,当函数终止时,其词法环境被破坏,并且num_birds_in_hand不再具有任何别名。)
而且,为了美观起见,每次调用f()时,我们都可以使用别名为不同对象值的x初始化其本地词法环境。

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

常量引用

这个引用可能会引起问题,有时我们需要某种承诺,即我的num_birds_in_hand***不会***被修改,即使我给出了它的别名。
这就是const形式参数的作用,通过用const标记形式参数,我们保证当函数被调用并且本地词法环境被创建时,它不会被用来改变实际的参数值。

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

引用参数的用途有两个:允许一个函数修改调用者词法环境中的值,并避免复制一些昂贵的(或不可复制的)东西。例如,标准库中的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标记形式参数名,但没有人关心这个函数。)
(That我说,有时候人们确实关心。在示例代码中,它确实告诉调用者ab在使用它们的值之前不会有奇怪的事情发生。但我认为这只是意味着调用者对函数的内部工作方式了解太多。据我所知,当 * 调用 * 一个函数时,这个函数是如何工作的,这对我来说应该是未知的魔法。)
然而,最终,按值传递的参数是否标记为const并不重要。

时间;日期

形式参数名被 * 初始化 * 为实际参数值 * 每次调用函数时 * -在函数代码执行之前,创建一个新的词法环境,该词法环境位于函数本地,将形式参数名绑定到实际参数值。(一旦函数return s,它的词法环境被破坏,程序控制返回给调用者。)

相关问题