变量

初始值

当对象在创建时获得了一个特定的值,我们说这个对象被初始化了。
用于初始化变量的值,可以是任意复杂的表达式。

初始化

初始化不是赋值的一种,事实上,C++语言中,初始化和赋值是两个完全不同的操作。然而在很多编程语言中二者的区别几乎可以忽略不计。但实际上,初始化这个概念至关重要。

初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来代替。

列表初始化

想要定义一个名为units_sold的int变量并初始化为0,下面4条语句都可以做到这一点:

int units_sold = 0;
int units_sold = {0};
int units_sold{0};
int units_sold(0);

当用于内置类型的变量时,这种初始化形式有一个重要的特点:如果我们使用列表初始化且初始值存在丢失信息的风险,则编译器将报错:

long double ld = 3.1415926;
int a{ld}, b={ld};  //错误:转换未执行,因为存在丢失信息的风险
int c{ld}, d = ld;  //正确:转换执行,且确实丢失了部分值

使用long double的值初始化int变量时可能丢失数据,所以编译器拒绝了a和b的初始化请求。其中,至少ld的小数部分会丢失掉,而且int也可能存不下ld的整数部分。

默认初始化

如果定义变量时没有指定初始值,则变量被默认初始化,此时变量被赋予了“默认值”。默认值到底是什么有变量类型决定,同时定义变量的位置也会对此有影响。
如果是内置类型的变量未被显式初始化,它的值由定义的位置决定。定义于任何函数体之外的变量被初始化为0。
一种情况是例外,定义在函数体内的内置类型变量将不被初始化。一个未被初始化的内置类型变量的值是未定义的,如果试图拷贝或以其他形式访问此类值将引发错误。
每个类各自决定其初始化对象的方式。而且,是否允许不经初始化就定义对象也由类自己决定。如果类允许这种行为,它将决定对象的初始值到底是什么。
绝大多数类都支持无须显式初始化而定义对象,这样的类提供了一个合适的默认值。例如,以刚刚所见为例,string类规定如果没有指定初值则生成一个空串:

std::string empty;  //empty非显式的初始化为一个空串
Sales_item item;  //被默认初始化的Sales_item对象

note:

定义于函数体内的内置类型的对象如果没有初始化,则其值未定义。类的对象如果没有显式的初始化,则其值由类确定

变量声明和定义的关系

分离式编译机制

该机制允许将程序分割为若干个文件,每个文件可被独立编译

变量声明和定义

声明使得名字为程序所知,一个文件文件如果想使用别处定义的名字则必须包含那个名字的声明。而定义负责创建与名字关联的实体。
变量声明规定了变量的类型和名字,在这一点上定义与之相同。但除此之外,定义还申请存储空间,也可能会为变量附一个初始值。
如果想声明一个变量而非定义它,就在变量名前添加关键字extern,而且不要显式的初始化变量:

extern int i;  //声明i而非定义i
int j;  //声明并定义j

任何包含了显式初始化的声明即成为定义。我们能给由external关键字标记的变量赋一个初始值,但是这么做也就抵消了external的作用。extern语句如果包含初始值就不再是声明,而变成了定义了:

extern double pi = 3.14;  //定义

在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误。
变量能且只能被定义一次,但是可以被多次声明。

标识符

C++的标识符由字母、数字和下划线组成,其中必须以字母或下划线开头。标识符的长度没有限制,但对大小写字母敏感:

//定义4各不同的int变量
int somename, someName, SomeName, SOMENAME;

同时,C++也为标准库保留了一些名字,用户自定义的标识符中不能连续出现两个下划线,也不能以下划线紧跟大写字母开头,此外,定义在函数体外的标识符不能以下划线开头。

变量命名规范

变量命名有许多约定俗称的规范,下面的这些规范可能有效提高程序的可读性:

  • 标识符要能体现实际含义
  • 变量名一般用小写字母,如index,不要使用Index或INDEX。
  • 用户自定义的类名一般以大写字母开头,如Sales_item。
  • 如果标识符由多个单词组成,则单词间应有明显区分,如student_loan或studentLoan,不要使用studentloan。

名字的作用域

不论是在程序的什么位置,使用到的每个名字都会指向一个特定的实体:变量、函数、类型等。然而,同一个名字如果出现在程序的不同位置,也可能指向的是不同实体。
作用域是程序的一部分,在其中名字有其特定的含义。C++语言中大多数作用域都以花括号分隔。
名字的有效区域始于名字的声明语句,以声明语句所在的作用域末端为结束。

#include <iostream>
int main()
{
	int sum = 0;  //sum用于存放从1到10所有数的和
	for (int val = 1; val <= 10; ++val)
		sum += val;  //等价于sum = sum + val
	std::cout <<"Sum of 1 to 10 inclusive is "
					<< sum << std::endl;
	return 0;
}

这段程序定义了3个名字:main、sum和val,同时使用了命名空间名字std,该空间提供了2个名字cout和cin供程序使用。
名字main定义于所有花括号之外,它和其他大多数定义在函数之外的名字一样拥有全局作用域。一旦声明之后,全局作用域内的名字在整个程序的范围内都可以使用。名字sum定义于main函数所限定的作用域之内,从声明sum开始直到main函数结束为止都可以访问它,但是出了main函数所在的块就无法访问了,因此说变量sum拥有块作用域。名字val定义于for语句内,在for语句之内可以访问val,但是在main函数的其他部分就不能访问它了。
一般来说,在对象第一次被使用的地方附近定义它是一种好的选择,因为这样做有助于更容易的找到变量的定义。更重要的是,当变量的定义与它第一次被使用的地方很近时,我们也会赋给它一个比较合理的初始值。

#include <iostream>
int reused = 42;
int main()
{
	int unique = 0;
	int reused = 0;
	//输出显式的访问全局变量reused;输出42 0
    std::cout <<::reused  <<" "<<unique << std::endl;
}

使用作用域操作符来覆盖默认的作用域规则,因为全局作用域本身并没有名字,所以当作用域操作符的左侧为空时,向全局作用域发出请求获取作用于操作符右侧名字对应的变量。结果是,第三条输出语句使用全局变量resused,输出42 0。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值