Home > C++, 编程语言 > C++ Primer 学习笔记:变量和类型

C++ Primer 学习笔记:变量和类型

C++ Primer 学习笔记一 :变量和基本类型

1. 在C++ 中要理解“初始化不是赋值”,因为初始化是指创建变量并给它赋初始值,而赋值是擦除对象的当前值并用新值代替。虽然只有在编写非常复杂的类时才能凸显这两种方式的区别,但这也是一个关键的概念,而且直接初始化更灵活而且效率更高。

C++中支持两种初始化的形式:复制初始化和直接初始化:

int ival(1024)  // direct-initialization
int ival = 1024  // copy-initialization

2. 在C++语言中,变量必须且仅能定义一次,而且在使用变量之前必须定义或声明变量。为了让多个文件访问相同的变量,C++区分了声明和定义。
a) 变量的定义用于为变量分配存储空间,还可以为变量指定初始值,在一个程序中,变量有且仅有一个定义。
b) 声明用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字,可以通过使用extern关键字声明变量名而不定义它:

extern int i; // declares but does not define i
int i; // declares and defines i

在这里,extern声明不是定义,也不分配存储空间,因为只有定义才分配存储空间。如果声明有初始化,则可以看作是定义:

extern double pi = 3.1416

虽然使用了extern,但是这条语句还是定义了pi,分配并初始化了存储空间,只有当extern声明位于函数外部时,才可以含有初始化式。
c) 任何在多个文件中使用的变量都需要有与定义分离的声明,在这种情况下,一个文件含有变量的定义,使用该变量的其它文件则包含此变量的声明(而不是定义)。
d) 通常把一个对象定义在它首次使用的地方,以提高可读性。放置声明的一个约束是,变量只能在其定义处开始到此声明所在的作用域的结束处才可以访问,必须在使用此变量的最外层作用域里面或之前定义变量。

3. 外部变量extern和const,非const变量默认为extern,而要使用const变量能在其它文件中访问,必须显示地指定它为extern。
即必须在最初就定义为:extern const int bufSize = 512;

4. 引用就是对象的另一个名字,在程序中它的主要用作函数的形式参数。引用是一种复合类型,通过在变量名前加 & 来定义,复合类型是指用其它类型定义的类型。在引用的情况下,每一种引用类型都“关联到”某一其它类型,不能定义引用类型的引用 ,但可以定义其它任何类型的引用。
引用必须用与该引用同类型的对象初始化:

	int ival = 1024;
	int &refVal = ival; // 正确
 	int &refVal2;  // 错误
	int & refVal3 = 10 // 错误

引用只是它绑定的对象的另一个名字,作用在引用上的所有操作事实上都是作用在该引用绑定的对象上,当引用初始化后,只要该引存在,它就保持绑定到初始化时指向的对象,不能将引用绑定到另一个对象。
要理解的一个重要概念是“引用只是对象的另一个名字”。
如果用const 修饰,则表示不能通过引用来修改所绑定的变量的值,而且,将普通的引用绑定到const对象也是不合法的:

const int ival = 1024;
const int &refVal = ival; // 合法,因为对象及引用都是const的
int &ref2 = ival;       // 非法,因为非const变量引用了一个const对象

Const引用可以初始化为不同类型的对象或者初始化为右值,如字面常量。

int i = 42;
const int &r = 42;
const int &r2 = r+i;

同样的初始化对于非const引用却是不合法的,下面解释它的原因:

double dval = 3.14;
const int &ri = dval;

编译器会把这些代码转换为:

int temp = dval;  // 建立一个临时变量,将ri绑定到临时变量。
const int &ri = temp;

即是说:非const引用只能绑定到与该引用同类型的对象,而const引用可以绑定到不同但相关的对象或绑定到右值。

double val = 42.999;
const int &r3 = val;
val = 2;
//r3 = 4; 非法
// 改变后 val = 2 而 r3 = 42

5. typedef 的三种目的:
a) 为了隐藏特定类型的实现,强调使用类型的目的。
b) 简化复杂的类型定义,使其更易理解。
c) 允许一种类型用于多个目的,同时使得每次使用该类型的目的明确。

6. 枚举成员是常量,默认情况下第一个枚举成员赋值为0,后面的每个枚举成员赋的值比前面的大1。但也可以为一个或多个枚举成员赋初值,用来初始化枚举成员的值必须是一个常量表达式(在编译时就能计算出结果的整形表达式)。
可以定义:

enum Form { shape = 1, sphere, cylinder, polygon } // 依次为1,2,3,4
enum Points { points2d = 2, point2w, point3d=3, point3w } // 依次为2,3,3,4

虽然枚举成员值可以是不唯一的,但是不能改变枚举成员的值,因为枚举成员的值本身就是一个常量表达式。而且枚举类型的对象的初始化赋值,只能通过其枚举成员或同一枚举类型的其它对象进行:如 Points p = points2d;

7. 头文件需要注意的地方:
a) 头文件用于声明而不是用于定义。
定义与声明的区别在于定义只能出现一次,而声明可以出现多次。下列语句是定义,不应当放在头文件里:

Extern int ival = 10  // initializer, so it’s a definition
double fica_rate;  // not extern, so it’s a definition

在同一个程序中有两个或两个以上文件中含有上述任何一个定义都会导致多重定义的链接错误。由于头文件包含在多个源文件中,所以不应该含有变量或者函数的定义。
但是对于头文件不包含定义这一规则,有三个例外。头文件可以定义类,值在编译时就已知的const对象和inline函数,这些实体可以在多个源文件中定义,只要每个源文件的定义是相同的。
在头文件中定义这些实体,是因为编译器需要它们的定义(不只是声明)来产生代码,例如为了产生能定义或者使用类的的对象的代码,编译器需要知道组成该类型的数据成员,同样还需要知道能够在这些对象上执行的操作,这些是由类定义来提供的。
b) 一些const对象定义在头文件中。
C++中,任何变量都只能定义一次,定义会分配存储空间,而所有对该变量的使用都关联到同一存储空间。Const对象默认为定义它的文件的局部变量,因而将它们放在头文件中是合法的。这种行为的重要意义在于,当我们在头文件中定义了const变量后,每个包含该头文件的源文件都有了自己的const变量,其名称和值都一样。
当该const变量是用常量表达式初始化时,可以保证所有的变量都有相同的值,但在实践中,大部份的编译器在编译时都会用相应的常量表达式替换对这些const变量的使用。所以在实践中不会有任何存储空间用于存储用常量表达式初始化的const变量。
如果const变量不是用常量表达式进行初始化,如const double sq2 = squt(2.0),那它就不应该放在头文件中而应该放在一个源文件中进行初始化,并在头文件中添加extern声明以让它能被多个文件共享。
c) 使用头文件保护符,以避免多重包含。

Related posts:

  1. C++ Primer 学习笔记:数组和指针 (2)
  2. C++ Primer 学习笔记:数组和指针 (1)
  3. C++ Primer 学习笔记:标准库类型
Categories: C++, 编程语言 Tags:
  1. No comments yet.
  1. No trackbacks yet.