[c++primer][02]变量和基本类型
C++是一种静态类型语言,编译时执行类型检查。
2.1 基本内置类型
内置类型:C++定义了一组表示整数、浮点数、单个字符、布尔值的算术类型,另外还定义了一种特殊类型void。其中,整数、字符和布尔值合称整型,字符类型分为char、w_char(用于扩展字符集)。
算术类型的存储空间大小依机器而定,C++标准规定了每个算术类型的最小存储空间,但并不阻止编译器使用更大的存储空间。
整型
一般地,short为半个机器字(word)长,int为一个机器字长,long为一个或两个机器字长,bool类型表示真值true和false,任意算术类型可赋值给bool对象,0值代表false,非0值代表true。
int、short、long默认为带符号型,无符号型须指定unsigned,unsigned默认表示unsigned int。需要注意的是,char有三种类型,但只有unsigned char和signed char两种表示方式。
对于unsigned类型来说,编译器必须调整越界值使其满足要求。在C++中,把负值赋给unsigned对象是完全合法的,其结果是该负数对该类型的取值个数求模后的值。
浮点型
一般,float用一个字表示,double用两个字表示,long double用三个或四个字表示。
建议:使用内置算术类型
1、计数时使用标准库定义的类型总是正确的。其它情况下,使用unsigned类型比较明智,可避免值越界导致结果为负;
2、使用short可能会隐含赋值越界的错误;虽然char是整型,但通常用来存储字符而不用于计算;
3、使用double类型基本上不会有错,在float类型中隐含的精度损失是不能忽略的,而双精度计算的代价相对于单精度可以忽略。
2.2 字面值常量
字面值常量用值来称呼且值不可修改,只有内置类型存在字面值,没有类类型的字面值。
整型,默认为int或long
20 //decimal
024 //octal
0x(0X)14 //hexadecimal
后缀L(l)代表long 后缀U(u)代表unsigned
浮点型,默认为double
3.14159E0f
指数用E(e),后缀F(f)代表精度,后缀L(l)代表扩展精度
布尔和字符
布尔:true、false
字符:前缀L代表宽字符型wchar_t ( L'a' )
另,为兼容C语言,C++字符串字面值都由编译器自动在末尾添加一个空字符;连接不同类型的字符串字面值的行为未定义;多行字面值用反斜线符号"\"连接。
2.3 变量
左值,可以出现在赋值语句左边或右边;右值,只能出现在赋值语句的右边。(变量是左值)
对象是内存中具有类型的区域。
初始化
int ival(1024); //复制初始化(copy) int ival = 1024; //直接初始化(direct)
初始化不是赋值!初始化指创建变量并给它赋初始值,赋值是擦除对象的当前值并用新值代替。
对内置类型来说,复制初始化和赋值初始化几乎没有区别;对类类型对象来说,有些初始化仅能用直接初始化完成。有多个初始化式时不能使用复制初始化。
初始化规则
1、内置类型
函数体外定义的变量自动初始化为0,函数体内定义的变量不进行自动初始化。除了用作赋值左操作数,未初始化变量任何其他用途都是未定义的。
2、类类型
定义某个类的变量时没有提供初始化式,会使用默认构造函数完成初始化,不管变量在哪定义,默认构造函数都会被使用;对没有默认构造函数的类类型,每个定义都必须提供显式的初始化式。
声明和定义
定义,为变量分配存储空间,还可以为变量指定初始值。(变量有且仅有一个定义)
声明,说明变量的类型和名字,可以通过extern关键字声明变量而不定义它,此时说明变量定义在程序的其它地方。
任何在多个文件中使用的变量声明与定义需要分离。一个文件中含有变量的定义,使用该变量的其他文件则包含该变量的声明。
只有当声明位于函数外部时,才可以含有初始化式,被当做是定义。
感受一把:
extern double pi = 3.1416; //defination double pi; //error, redefination extern double pi; //ok, declaration extern double pi = 3.1416; //error, redefination
名字的作用域
定义在函数外部的名字具有全局作用域,定义在函数内的名字具有局部作用域,定义在语句内的名字具有语句作用域。
局部变量最好使用不同的名字;通常把一个对象定义在它首次使用的地方是个很好的办法。
2.4 const限定符
const对象在定义后不能被修改,故定义时必须初始化。
默认情况下,在全局作用域声明的const变量是定义该对象的文件的局部变量,只存在于所在文件,不能被其它文件访问。
非const变量默认为extern。要使const变量也能够在其他文件中访问,必须显式地指定它为extern。
2.5 引用
1、引用只是它绑定的对象的另一名字
2、必须在定义引用时进行初始化
3、const引用是指向const对象的引用
int i = 42; //以下两句只对const引用合法 const int &r = 42; const int &r2 = r + i;
4、仅允许const引用绑定到需要临时变量作为媒介来完全绑定过程的值,因为const引用是只读的。
double dval = 3.14; int &ri = dval; //error: invalid initialization of reference of type ‘int&’ from expression of type ‘double’
非const引用只能绑定到与该引用同类型的对象。const引用可以绑定到不同但相关的类型的对象或绑定到右值。
2.6 typedef名字
用法:
typedef 数据类型 标识符
用来指明现有数据类型的同义词
2.7 enum枚举
用法:
enum 枚举类型名 {枚举成员1,枚举成员2,,,,}
1、默认地,第一个枚举成员赋值为0,后面的每个成员比前面大1;
2、必须用常量表达式初始化枚举成员;
3、枚举类型对象的初始化或赋值,只能通过其枚举成员或同一枚举类型的其他对象来进行;
常量表达式是编译器在编译时就能够计算出结果的表达式。
2.8 类类型
1、每个类都定义了一个接口和一个实现。接口由使用该类的代码需要执行的操作组成。实现一般包括该类所需要的数据,以及定义该类需要的但又不供一般性使用的函数。
2、设计类的步骤:
1)定义操作;2)确定所需要的数据;3)确定用来支持该类实现的函数
3、定义类的花括号后面跟一个分号。每个类都定义了它的作用域,数据和操作的名字在类的内部必须唯一,但可以重用定义在类外的名字。
4、定义数据成员时,只能指定该数据成员的名字和类型。类不是在类定义里定义数据成员时初始化数据成员,而是通过构造函数控制初始化
5、struct与class的区别
默认访问级别不同,默认情况下,struct的成员为public,class的成员为private 。
2.9 编写自己的头文件
头文件包含:类的定义、extern变量的声明、函数的声明;头文件用于声明而不是用于定义。
1 extern int ival = 10; //definition 2 double fica_rate; //definition
同一个程序中有两个以上文件含有上述任一个定义都会导致多重定义链接错误。
因为头文件包含在多个源文件中,所以不应该含有变量或函数的定义。BUT,有三个例外,头文件可以定义类、值在编译时就已知的const对象和inline函数。
在头文件中定义了const变量后,每个包含该头文件的源文件都有了自己的const变量,其名称和值都一样。当const变量是用常量表达式初始化时,可保证所有变量都有相同的值。在实践中,大部分编译器在编译时会用相应的常量表达式替换对const变量的使用,故不会有任何存储空间用来存储这个const变量。(如果const变量不是用常量表达式初始化,那么它就不应该在头文件中定义。)