[英]Why do const variables don't need to be initialized in a template class until the class is actually used?
[英]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
的东西.
此外,这是对底层工作方式的极大简化,但它是语言看待宇宙的方式,也是程序员通常应该如何看待的方式。
现在更多的词汇。 一个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
现在与两个名称( x
和y
)相关联,其中任何一个都可用于访问 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_hand
和x
)相关联,其中任何一个都可用于访问 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 )
将a
和b
标记为const
确实没有多大意义——没有人关心add()
对其实际参数值的本地副本做了什么。
(有时编写函数代码的人很关心,所以他或她会用const
标记正式参数名称。但是没有人使用function 关心。)
(也就是说,有时人们确实关心。在示例代码中,它确实告诉调用者a
和b
在使用它们的值之前不会对它们做任何奇怪的事情。但我认为这只是意味着调用者也知道很多关于函数的内部工作。据我所知,当调用function 时,function 是如何工作的对我来说应该是未知的魔法。)
然而,最终,值传递 arguments 是否标记为const
并不重要。
每次调用 function 时,都会使用实际参数值初始化形式参数名称——在执行函数代码之前,创建一个新的局部于 function 的词法环境,将形式参数名称绑定到实际参数值。 (一旦 function return
s,它的词法环境就被破坏,程序控制权返回给调用者。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.