变量
变量
变量提供了程序可以操作的有名字的存储区。C++ 中的每一个变量都有特定的类型,该类型决定了变量的内存大小和布局、能够存储于该内存中的值的取值范围以及可应用在该变量上的操作集。C++ 程序员常常把变量称为“变量”或“对象(object)”。
左值和右值
左值(发音为 ell-value):左值可以出现在赋值语句的左边或右边。
右值(发音为 are-value):右值只能出现在赋值的右边,不能出现在赋值语句的左边。
变量是左值,因此可以出现在赋值语句的左边。数字字面值是右值,因此不能被赋值。
变量名
变量名,即变量的标识符,可以由字母、数字和下划线组成。变量名必须以字母或下划线开头,并且区分大小写字母:C++ 中的标识符都是大小写敏感的。
C++ 保留了一组词用作该语言的关键字。关键字不能用作程序的标识符。
asm |
do |
if |
return |
try |
auto |
double |
inline |
short |
typedef |
bool |
dynamic_cast |
int |
signed |
typeid |
break |
else |
long |
sizeof |
typename |
case |
enum |
mutable |
static |
union |
catch |
explicit |
namespace |
static_cast |
unsigned |
char |
export |
new |
struct |
using |
class |
extern |
operator |
switch |
virtual |
const |
false |
private |
template |
void |
const_cast |
float |
protected |
this |
volatile |
continue |
for |
public |
throw |
wchar_t |
default |
friend |
register |
true |
while |
delete |
goto |
reinterpret_cast |
C++ 还保留了一些词用作各种操作符的替代名。这些替代名用于支持某些不支持标准 C++操作符号集的字符集。它们也不能用作标识符。
and |
bitand |
compl |
not_eq |
or_eq |
xor_eq |
and_eq |
bitor |
not |
or |
xor |
除了关键字,C++ 标准还保留了一组标识符用于标准库。标识符不能包含两个连续的下划线,也不能以下划线开头后面紧跟一个大写字母。有些标识符(在函数外定义的标识符)不能以下划线开头。
变量定义与初始化
变量定义
变量定义的基本形式是:
由类型说明符开始,后面紧跟着以逗号分开的含有一个或多个说明符的列表,以分号结束定义。
例如:
int units_sold;
double sales_price, avg_price;
std::string title;
Sales_item curr_book;
多个变量可以定义在同一条语句中:
double salary, wage; // 定义两个double类型的变量
int month,
day, year; //定义三个int类型的变量
变量初始化
变量定义指定了变量的类型和标识符,也可以为对象提供初始值。定义时指定了初始值的对象被称为是已初始化的。
需要注意的是;“初始化不是赋值”。初始化指创建变量并给它赋初始值,而赋值则是擦除对象的当前值并用新值代替。
列表初始化
C++定义了好几种初始化的形式,例如:
int a = 10;
int a = { 10 };
int a(10);
int a{ 10 };
作为C++11新标准的一部分,用花括号来初始化变量得到了广泛的应用,无论是初始化对象,还是某些时候为对象赋新值,都可以使用这样一组由花括号括起来的初始值。
使用列表初始化且初始值存在丢失信息的风险,则编译将报错:
long double ld = 3.1415926;
int a{ ld }, b = { ld }; //错误,转换未执行,因为存在丢失信息
int c(ld), d = ld; //正确,转换执行,且确实丢失了部分值
默认初始化
如果变量定义时没有指定初值,则变量被默认初始化,此时变量被赋予了默认值,默认值到底是什么由变量类型决定,同时变量定义的位置也会对此有影响。
如果是内置类型的变量未被初始化,它的值由定义的位置决定,定义于任何函数体之外的变量被初始化为0,定义于函数体内部的内置变量不被初始化。一个未被初始化的内置类型变量的值是未定义的,如果试图拷贝或以其它形式访问此值将引发错误。
如果定义某个类的变量时没有提供初始化式,这个类也可以定义初始化时的操作。它是通过定义一个特殊的构造函数即默认构造函数来实现的。这个构造函数之所以被称作默认构造函数,是因为它是“默认”运行的。如果没有提供初始化式,那么就会使用默认构造函数。不管变量在哪里定义,默认构造函数都会被使用。
初始化多个变量
当一个定义中定义了两个以上变量的时候,每个变量都可能有自己的初始化式。
对象被定义后的名字立即变成可见,所以可以用同一个定义中前面已定义变量的值初始化后面的变量。已初始化变量和未初始化变量可以在同一个定义中定义。
int interval,
month = 8, day = 7, year = 1955;
double salary = 9999.99,
wage(salary + 0.01);
变量的声明和定义
C++ 程序通常由许多文件组成。为了让多个文件访问相同的变量,C++ 区分了声明和定义。
变量的定义用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且仅有一个定义。
声明用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用 extern 关键字声明变量名而不定义它。
extern int i; //声明而非定义i
int i; //声明并且定义i
extern 声明不是定义,也不分配存储空间。事实上,它只是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。
只有当声明也是定义时,声明才可以有初始化式,因为只有定义才分配存储空间。初始化式必须要有存储空间来进行初始化。如果声明有初始化式,那么它可被当作是定义,即使声明标记为 extern:
extern double pi = 3.1416; //定义
虽然使用了 extern ,但是这条语句还是定义了 pi,分配并初始化了存储空间。只有当 extern 声明位于函数外部时,才可以含有初始化式。
因为已初始化的 extern 声明被当作是定义,所以该变量任何随后的定义都是错误的:
extern double pi = 3.1416; // definition
double pi; // error: redefinition of pi
同样,随后的含有初始化式的 extern 声明也是错误的:
extern double pi = 3.1416; // definition
extern double pi; // ok: declaration not definition
extern double pi = 3.1416; // error: redefinition of pi
任何在多个文件中使用的变量都需要有与定义分离的声明。在这种情况下,一个文件含有变量的定义,使用该变量的其他文件则包含该变量的声明(而不是定义)。
名字的作用域
C++程序中,每个名字都与唯一的实体(比如变量、函数和类型等)相关联。尽管有这样的要求,还是可以在程序中多次使用同一个名字,只要它用在不同的上下文中,且通过这些上下文可以区分该名字的不同意义。用来区分名字的不同意义的上下文称为作用域。作用域是程序的一段区域。一个名称可以和不同作用域中的不同实体相关联。
定义在所有函数外部的名字具有全局作用域,可以在程序中的任何地方访问。定义于函数体内的名字具有块作用域。
C++ 中作用域嵌套
作用域能够彼此包含,被包含(或者说被嵌套)的作用域称为内层作用域,包含着别的作用域的作用域称为外层作用域。
作用域中一旦声明了某个名字,它所嵌套着的所有作用域中都能访问该名字,同时允许在内层作用域中重新定义外层作用域已有的名字,此时内层作用域定义的名字将会覆盖外层作用域的定义。
在变量使用处定义变量
一般来说,变量的定义或声明可以放在程序中能摆放语句的任何位置。变量在使用前必须先声明或定义。
通常把一个对象定义在它首次使用的地方是一个很好的办法。
在对象第一次被使用的地方定义对象可以提高程序的可读性。读者不需要返回到代码段的开始位置去寻找某一特殊变量的定义,而且,在此处定义变量,更容易给它赋以有意义的初始值。