【Learncpp中文翻译版】【1.4变量赋值和初始化】

原文链接:原文链接

声明:

  • 本文旨在方便了解学习C++语法,切勿用于任何商业用途。
  • 由于本人英语水平有限,文章中可能存在语义错误,如有疑问请参照原文,也可以在评论区指出错误。

1.4——变量赋值和初始化

在上一课(1.3 - 对象和变量简介)中,我们介绍了如何定义可用于存储值的变量。在本课中,我们将探讨如何将值实际放入变量并使用这些值。

提醒一下,这里有一个简短的片段,它首先分配一个名为x的整数变量,然后再分配两个名为y和z的整数变量:

int x; // define an integer variable named x
int y, z; // define two integer variables, named y and z

变量赋值

定义变量后,您可以使用 = 运算符为其赋值(在单独的语句中) 。这个过程简称为拷贝赋值(或简称为赋值)。

int width; // define an integer variable named width
width = 5; // copy assignment of value 5 into variable width

// variable width now has value 5

复制赋值之所以如此命名,是因为它将 = 运算符右侧的值复制到运算符左侧的变量中。= 运算符称为赋值运算符

这是一个我们使用两次赋值的例子:

#include <iostream>

int main()
{
	int width;
	width = 5; // copy assignment of value 5 into variable width

	// variable width now has value 5

	width = 7; // change value stored in variable width to 7

	// variable width now has value 7

	return 0;
}

当我们将值 7 分配给变量width时,之前的值 5 将被覆盖。普通变量一次只能保存一个值。

警告

新程序员最常犯的错误之一是将赋值运算符 ( = ) 与相等运算符 ( == ) 混淆。赋值 ( = ) 用于为变量赋值。 ( == ) 用于测试两个操作数的值是否相等。

初始化

赋值的一个缺点是它至少需要两条语句:一条用于定义变量,一条用于赋值。

这两个步骤可以结合起来。定义变量时,您还可以同时为变量提供初始值。这称为初始化。用于初始化变量的值称为初始化器。

C++ 中的初始化非常复杂,因此我们将在此处提供一个简化的视图。

在 C++ 中初始化变量有 4 种基本方法:

int a; // no initializer
int b = 5; // initializer after equals sign
int c( 6 ); // initializer in parenthesis
int d { 7 }; // initializer in braces

您可能会看到上面的表格以不同的间距书写(例如int d{7};)。您是否使用额外的空间来提高可读性是个人喜好的问题。


默认初始化

当没有提供初始化值时(例如上面的变量a),这称为默认初始化。在大多数情况下,默认初始化会留下一个具有不确定值的变量。我们将在课程中进一步介绍这种情况(1.6 - 未初始化的变量和未定义的行为)。


拷贝初始化

当等号后提供初始化器时,这称为拷贝初始化。拷贝初始化继承自 C 语言。

int width = 5; // copy initialization of value 5 into variable width

与拷贝赋值非常相似,这会将右侧的值拷贝到左侧正在创建的变量中。在上面的代码片段中,变量 width 将被初始化值为 5。

拷贝初始化在现代 C++ 中使用不多。但是,您可能仍会在较旧的代码中或在首先学习 C 的开发人员编写的代码中看到它。


直接初始化

当括号内提供初始化器时,这称为直接初始化

int width( 5 ); // direct initialization of value 5 into variable width

最初引入直接初始化是为了更有效地初始化复杂对象(那些具有类类型的对象,我们将在以后的章节中介绍)。然而,与复制初始化一样,直接初始化在现代 C++ 中并没有太多使用(除了一种特殊情况,我们将在谈到它时介绍)。


大括号初始化

在 C++ 中初始化对象的现代方法是使用一种利用大括号的初始化形式:大括号初始化(也称为统一初始化或列表初始化)。

大括号初始化有三种形式:

int width { 5 }; // direct brace initialization of value 5 into variable width (preferred)
//直接将值 5 的大括号初始化为可变的 width(首选)
int height = { 6 }; // copy brace initialization of value 6 into variable height
//将值 6 的大括号初始化复制到可变的 height
int depth {}; // value initialization (see next section)
//值初始化(见下一节)
直接和复制大括号初始化几乎相同,但通常首选直接形式。你能解释一下这很重要吗?

答案:初始化类对象时,直接大括号初始化可以使用显式构造函数,复制大括号初始化不能。
#include <iostream>

class Foo
{
public:
    Foo(int) {}
    explicit Foo(double) {}
};

int main()
{
    Foo f1{ 5 }; // ok
    Foo f2{ 1.2 }; // ok
    Foo f3 = { 5 }; // ok
    Foo f4 = { 1.2 }; // won't work, copy brace init can't use explicit constructors

    return 0;
}

作为旁白…

在引入大括号初始化之前,某些类型的初始化需要使用复制初始化,而其他类型的初始化需要使用直接初始化。引入大括号初始化是为了为所有特性提供更​​一致的初始化语法(这就是为什么它有时被称为 “统一初始化” ,尽管它并没有完全实现这个目标)。此外,大括号初始化提供了一种使用值列表初始化对象的方法(这就是它有时被称为 “列表初始化” 的原因)。

大括号初始化还有一个额外的好处:它不允许“缩小转换”。这意味着如果您尝试使用变量无法安全保存的值来初始化变量,编译器将产生错误。例如:

int width { 4.5 }; // error: a number with a fractional value can't fit into an int

在上面的代码片段中,我们试图将一个具有小数部分(0.5 部分)的数字(4.5)分配给一个整数变量(它只能保存没有小数部分的数字)。

复制和直接初始化只会删除小数部分,导致将值 4 初始化为可变width(您的编译器可能会对此产生警告,因为很少需要丢失数据)。但是,使用大括号初始化时,编译器将生成一个错误,迫使您在继续之前修复此问题。

允许在没有潜在数据丢失的情况下进行转换。


值初始化和零初始化

当一个变量用空括号初始化时,就会发生值初始化。在大多数情况下,值初始化会将变量初始化为零(或空,如果这更适合给定类型)。在发生归零的这种情况下,这称为归零初始化

int width {}; // zero initialization to value 0
问:我什么时候应该用 { 0 } vs {} 初始化?

如果您实际使用该值,请使用显式初始化值。

int x { 0 }; // explicit initialization to value 0
std::cout << x; // we're using that zero value

如果值是临时的并且将被替换,则使用值初始化。

int x {}; // value initialization
std::cin >> x; // we're immediately replacing that value

初始化变量

在创建时初始化您的变量。您最终可能会发现出于特定原因(例如,使用大量变量的代码的性能关键部分)想要忽略此建议的情况,这没关系,只要是故意做出的选择。

有关此主题的更多讨论,Bjarne Stroustrup(C++ 的创建者)和 Herb Sutter(C++ 专家)在此处自己提出此建议。

第1.6 课——未初始化的变量和未定义的行为中,我们探讨了如果您尝试使用没有明确定义值的变量会发生什么。


初始化多个变量

在上一节中,我们注意到可以在单个语句中定义多个相同类型的变量,方法是用逗号分隔名称:

int a, b;

我们还注意到,最佳实践是完全避免这种语法。但是,由于您可能会遇到使用这种风格的其他代码,所以多谈一下它仍然很有用,如果没有其他原因,只是为了强调一些您应该避免使用它的原因。

您可以初始化在同一行上定义的多个变量:

int a = 5, b = 6; // copy initialization
int c( 7 ), d( 8 ); // direct initialization
int e { 9 }, f { 10 }; // brace initialization (preferred)

不幸的是,当程序员错误地尝试使用一个初始化语句来初始化这两个变量时,可能会出现一个常见的陷阱:

int a, b = 5; // wrong (a is not initialized!)

int a = 5, b = 5; // correct

在上面的语句中,变量“a”将未初始化,编译器可能会或可能不会抱怨。如果没有,这是让您的程序间歇性崩溃并产生零星结果的好方法。我们将更多地讨论如果您稍后使用未初始化的变量会发生什么。

记住这是错误的最好方法是考虑直接初始化或大括号初始化的情况:

int a, b( 5 );
int c, d{ 5 };

这使得值 5 仅用于初始化变量b或d而不是a或c似乎更清楚一点。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值