2.2.1 变量定义
变量定义的基本形式是:首先是类型说明符(type specifier),随后紧跟由一个或多个变量名组成的列表,其中变量名以逗号分隔,最后以分号结束。列表中每个变量名的类型都由类型说明符指定,定义时还可以为一个或多个变量赋初值:
int sum = 0 value // sum、value和units_sold都是int
units_sold = 0;// sum和units_sold初值为0
Sales_item item;// item的类型是Sales_item(参见1.5.1节,第17页)
// string是一种库类型,表示一个可变长的字符序列
std::string book("0-201-78345-X"); // book通过一个string字面值初始化
book的定义用到了库类型std::string,想iostream(参见1.2节,第6页)一样,string也是在命名空间std中定义的,我们将在第3章中对string类型做更详细的介绍。眼下,只需了解string是一种表示可变长字符序列的数据类型就可以了。C++库提供了几种初始化string对象的方法,其中一种是把字面值拷贝给string对象(参见2.1.3节,第36页),因此在上例中,book被初始化为0-201-78345-X。
术语:何为对象?
C++程序员们在很多场合都会使用对象(object)这个名词。通常情况下,对象是指一块能存储数据并具有某种类型的内存空间。
一些人仅在与类有关的场景下才使用“对象”这个词。另一些人则已把命名的对象和未命名的对象区分开来,他们把命名了的对象叫做变量。还有一些人把对象和值区分开来,其中对象指能被程序修改的数据,而值(value)指只读的数据。
本书遵循大多数人的习惯用法,即认为对象是具有某种数据类型的内存空间。我们在使用对象这个词时,并不严格区分是类还是内置类型,也不区分是否命名或是是否只读。
初始值
当对象在创建时获得了一个特定的值,我们说这个对象被初始化(initialized)了。用于初始化变量的值可以是任意复杂的表达式。当一次定义了两个或多个变量时,对象的名字随着定义也就马上可以使用了。因此在同一条定义语句中,可以用先定义的变量去初始化后定义的其他变量。
// 正确:price先被定义并赋值,随后被用于初始化discount
double price = 109.99 discount = price * 0.16;
// 正确:调用函数applyDiscount,然后用函数的返回值初始化salePrice
double salePrice = applyDiscount(price discount);
在C++语言中,初始化是一个异常复杂的问题,我们也将反复讨论这个问题。很多程序员对于用等号=来初始化变量的方式倍感困惑,这种方式容易让人认为初始化是赋值的一种。事实上在C++语言中,初始化和赋值是两个完全不同的操作。然而在很多编程语言中二者的区别几乎可以忽略不计,即使在C++语言中又是这种区别也无关紧要,所以人们特别容易把二者混为一谈。需要强调的是,这个概念至关重要,我们也将在后面不止一次提及这一点。
WARNING:初始化不是赋值,初始化的含义是创建变量时赋予其一贯初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。
列表初始化
C++语言定义了初始化的好几种不同形式,这也是初始化问题复杂性的一个体现。例如,要想定义一个名为units_sold的int变量并初始化为0,以下的4条语句都可以做到这一点:
int units_sold = 0;
int units_sold = {0};
int units_sold{0};
int units_sold(0);
作为C++11新标准的一部分,用花括号来初始化变量得到了全面应用,而在此之前,这种初始化的形式仅在某些受限的场合下才能使用。出于3.3.1节(第88页)将要介绍的原因,这种初始化的形式被称为列表初始化(list initialization)。现在,无论是初始化对象还是某些时候为对象赋新值,都可以使用这样一组由花括号括起来的初始值了。
当用于内置类型的变量时,这种初始化形式有一个重要的特点:如果我们使用列表初始化切初始值存在丢失信息的风险,则编译器将报错:
long double ld = 3.1415926536;
int a{ld} b = {ld}; // 错误:转换未执行,因为存在丢失信息的危险
int c(ld) d = ld; // 正确:转化执行,且确实丢失了部分值
使用long double的值初始化int变量时可能丢失数据,所以编译器拒绝了a和b的初始化int变量。然而,像第16章介绍的一样,这种初始化有可能在不经意间发生。我们将在3.2.1节(第76页)和3.3.1节(第88页)对列表初始化做更多介绍。
默认初始化
如果定义变量是没有指定初值,则变量被默认初始化(default initialized),此时变量被赋予了“默认值”。默认值到底是什么由变量类型决定,同时定义变量的位置也会对此有影响。
如果是内置类型的变量未被显式初始化,它的值由定义的位置决定。定义于任何函数体之外的变量被初始化为0。然而如6.1.1节(第185页)所示,一种例外情况是,定义在函数体内部的内置类型变量将不被初始化(uninitialized)。一个未被初始化的内置类型变量的值是未定义的(参见2.1.2节,第33页),如果识图拷贝或以其他形式访问此类值将引发错误。
每个类各自觉得其初始化对象的方式。而且,是否允许不经初始化就定义对象也由类自己决定。如果类允许这种行为,它将决定对象的初始值到底是什么。
绝大多数类都支持无须显式初始化而定义对象,这样的类提供了一个合适的默认值。例如,以刚刚所见为例,string类规定如果没有指定初值则生成一个空串:
std::string empty; // empty非显式地初始化为一个空串
Sales_item item; // 被默认初始化的Sales_item对象
一些类要求每个对象都显式初始化,此时如果创建了一个该类的对象而未对其做明确的初始化操作,将引发错误。
NOTE:定义于函数体内的内置类型的对象如果没有初始化,则其值未定义。类的对象如果没有显式地初始化,则其值由类确定。
普通的冒险故事提示您:看后求收藏(卧龙小说网http://www.wolongxs.com),接着再看更方便。
好书推荐:《我的剧本世界在自主运行》、《我是舰娘》、《交错世界之学院都市》、《认清现实后,她们开始追夫火葬场》、《好徒儿你就饶了为师伐》、《带着修真界仙子们天下无敌》、《剑来》、《修炼成仙的我只想养成女徒弟》、《足控勇者的目标是魔王的丝袜》、《被触手怪养大的少女》、