C++之变量(2.2)

声明:本文是学习《C++ Primer》(王刚 杨巨峰译)过程中记录下的摘抄笔记。感谢两位译者翻译之功!

变量提供一个具名的、可供程序操作的存储空间。C++的每个变量都有自己的数据类型,数据类型决定着变量所占内存空间的大小和布局方式、该空间能存储的值的范围、变量能参与的运算。对C++程序员来说,“变量”和“对象"可以互换使用。

变量定义

变量定义的基本形式是:首先是类型说明符,随后紧跟一个或多个变量名组成的列表,变量名之间以逗号分隔,最后以分号结束。列表中每个变量名的类型都由类型说明符指定,定义时可以为一个或多个变量赋值。

int sum  = 0, value , unit_sold = 10;// 定义多个int类型变量,并赋值
int price = 3; // 定义一个变量并赋值

何为对象?
一般来说,对象是指一块能存储数据并具有某种类型的内存空间。我们在使用对象这个词时,并不严格区分是类还是内置类型,也不区分是否命名或是否只读。

初始值

当对象在创建时获得了一个特定的值,我们就说这个对象被初始化了。用于初始化变量的值可以是任意复杂的表达式。当一次定义了两个或多个变量时,对象的名字随着定义马上就可以使用。因此在同一条定义语句中,可以用先定义的变量值去初始化后定义的其他变量。

//正确,price先被定义并赋值,随后被用于初始化discount
double price = 109.99,discount = price * 0.9;
//正确,调用函数applyDiscount,然后用函数的返回值初始化salePrice
double salePrice = applyDiscount(price,discount);

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

列表初始化

C++语言定义了初始化的好几种不同形式,例如定义一个名为units_sold变量并初始化为0,可表示如下:

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

使用花括号初始化变量的形式被称为列表初始化,现在无论是初始化对象还是为对象赋值,都可以使用这样一组由花括号括起来的初始值了。

当用于内置类型的变量时,如果使用列表初始化且初始值存在丢失信息的风险,编译器将会报错:

long double ld = 3.141592636;
int a{ld}, b = {ld};//错误,转换失败,因为存在信息丢失风险
int c(ld), d = ld;//正确,转换成功,且确实丢失了部分数据

默认初始化

如果定义变量时没有指定初始值,则变量被默认初始化,此时变量被赋予了“默认值”。默认值到底是什么由变量类型决定,同时定义变量的位置也会对此有所影响。

如果是内置类型的变量未被显式初始化,它的值由定义的位置决定。定义于任何函数体外的变量都被初始化为0;定义于函数体内的变量将不被初始化。一个未被初始化的内置类型是未定义的,如果试图拷贝或以其他形式访问该类型变量将引发错误。

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

未初始化地变量含有一个不确定的值,使用未初始化变量的值是一种错误的编译行为且很难调试。建议初始化每一个内置类型的变量。虽然并非必须如此,但如果我们不能确保初始化后程序安全,那么这么做不失为一种简单可靠的方法。

变量声明和定义的关系

为了允许把程序拆分成多个逻辑部分来编写,C++语言支持分离式编译机制,该机制允许把程序分割成若干个文件,每个文件可被独立编译。

如果将程序分割成多个文件,则需要有在文件间共享代码的方法。如,一个文件的代码可能需要使用另一个文件中的一个变量。实际的例子如std::cout和std::cin。

为了支持分离式编译,C++语言将声明和定义区分开来。声明使得名字为程序所知,一个文件如果想要使用别处定义的名字则必须包含对那个名字的声明。而定义负责创建与名字关联的实体

变量声明定义了变量的类型和名字,在这一定上与定义相同。但除此之外,定义还申请存储空间,也可能会为变量赋一个初始值。

如果想声明一个变量而非定义它,就在变量名前添加关键字extern,而且不要显式地初始化变量:

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

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

extern double pi = 3.14;// 定义

变量能且只能被定义一次,但是可被多次声明

声明和定义地区别看起来也许微不足道,但实际上非常重要。如果要在多个文件中使用同一个变量,就必须将声明和定义分离。此时,变量的定义必须出现在且只能出现在一个文件中,而且他用到该变量的文件必须对其进行声明,却绝对不能重复定义

标识符

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

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

变量命名规范

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

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

名字的作用域

不论是在程序的什么位置,使用到的每个名字都会指向一个特定的实体:变量、函数、类型等。然而,同一个名字如果出现在程序的不同位置,也可能指向的是不同实体。

作用域(scope)是程序的一部分,在其中名字由其特定含义。C++语言中大多数作用域都以花括号分隔。

同一个名字在不同的作用域中可能指向不同的实体。名字的有效区域始于名字的声明语句,以声明语句所在的作用域末端为结束。

#include 

using namespace std;

int main()
{
    int sum = 0;
    // sum 用于存放从1到10所有数字之和
    for (int val = 1;val <= 10;val++)
    {
        sum += val;
    }
    cout << "Sum of 1 t0 10 inclusive is" << sum << endl;
    return 0;
}

这段程序定义了三个名字:main、sum和val,同时使用了命名空间名字std,该空间提供了2个名字cout和cin供程序使用。

main定义于所有花括号之外,它和其他大多数定义在函数体之外的名字一样拥有全局作用域(global scope)。一旦声明之后,全局作用域内的名字在整个程序的范围内都可食用。名字sum定义于main函数限定的作用域内,从声明sum开始到main函数结束为止都可访问它,但是出了main函数范围便无法访问了,因此说变量sum拥有块作用域(block scope)。名字val定义于for语句内,在for语句之内可以访问val,但是在main函数的其他部分就不能访问它了。

嵌套的作用域

作用域能彼此包含,被包含的作用域成为内层作用域(innner scope),包含着其他作用域的作用域称之为外层作用域(outer scope)

作用域中一旦声明了某个名字,它所嵌套的所有作用域中都能访问该名字。同时,允许在内存作用域中重新定义外层作用域已有的名字。

如下

#include 

using namespace std;

// 该程序仅用于说明,函数内部不宜定义与全局变量同名的新变量
int reused = 42;// reused拥有全局作用域
int main()
{
    int uniqu = 0;//uniqu拥有块作用域
    //输出#1:使用全局变量reused;输出42 0
    cout << reused << "" << uniqu << endl;
    int reused = 0;//新建局部变量,覆盖了全局变量reused
    //输出#2:使用局部变量reused;输出0 0
    cout << reused << "" << uniqu << endl;
    //输出#3:显式地访问全局变量reused;输出42 0
    coud << ::reused << "" << uniqu << endl;
    return 0;
}

如果函数有可能用到某全局变量,则不宜再定义一个同名地局部变量

你可能感兴趣的:(C++之变量(2.2))