赞
踩
原文链接:原文链接
声明:
- 本文旨在方便了解学习C++语法,切勿用于任何商业用途。
- 由于本人英语水平有限,文章中可能存在语义错误,如有疑问请参照原文,也可以在评论区指出错误。
在上一课(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似乎更清楚一点。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。