声明和定义
C++程序通常由许多文件组成,为了让多个文件访问相同的变量,C++区分了声明和定义。
变量的定义(definition)用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且仅有一个定义。C++支持两种初始化变量的形式:复制初始化(copy-initialization)和直接初始化(direct-initialization);复制初始化语法用等号=,直接初始化则是把初始化式放在括号()中。
声明(declaration)用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。
可以通过extern关键字声明变量名而不定义它(不分配存储空间)。只有当extern声明位于函数外部时,才可以含有初始化式。而如果声明有初始化式,则它被认为是定义。
名字的作用域
C++程序中,每个名字都与唯一的实体(比如变量、函数和类型等)相关联。尽管有这样的要求,还是可以在程序中多次使用同一个名字,只要它用在不同的上下文中,且通过这些上下文可以区分该名字的不同意义。用来区分名字的不同意义的上下文称为作用域(scope),作用域是程序的一段区域。一个名称可以和不同作用域中的不同实体相关联。
定义在所有函数外部的名字具有全局作用域(global scope),此外还有局部作用域(local scope)和语句作用域(statement scope)。C++还有另外两种不同级别的作用域:类作用域(class scope)和命名空间作用域(namespace scope)。
C++中作用域可嵌套,即定义在全局作用域中的名字可以在局部作用域中使用,定义在全局作用域中的名字和定义在函数的局部作用域中的名字可以在语句作用域中使用,等等。[ 在函数内定义一个与函数可能会用到的全局变量同名的局部变量总是不好的,局部变量最好使用不同的名字。 ]
枚举
默认地,第一个枚举成员赋值为0,后面的每个枚举成员赋的值比前面的大1。枚举成员值可以是不唯一的。
头文件
在程序中,定义只可以出现一次,而声明可以出现多次,所以定义不应该放在头文件里。同一个程序中有两个以上文件含有任一个相同的定义都会导致多重定义链接错误。对于头文件不应该含有定义这一规则,有三个例外:类、编译时已知道值的const对象和inline函数。这些实体可以在多个源文件中定义,只要每个源文件中的定义是相同的。
在头文件中定义这些实体,是因为编译器需要它们的定义(不只是声明)来产生代码。比如:为了产生能定义或使用类的对象的代码,编译器需要知道组成该类型的数据成员,以及在这些对象上执行的操作。这些信息需要类定义提供。
一般来说,常量表达式是编译器在编译时就能够计算出结果的表达式。当const变量通过常量表达式自我初始化时,这个const变量就可能是常量表达式。为了能够让多个文件使用相同的常量值,const变量和它的初始化式必须是每个文件都可见的。而要使初始化式可见,一般都把这样的const变量定义在头文件,则无论该const变量何时使用,编译器都能够看见其初始化式。然而,C++中的任何变量都只能定义一次,定义会分配存储空间,而所有对该变量的使用都关联到同一存储空间。但因为const对象默认为定义它的文件的局部变量,所以把它们的定义放在头文件是合法的,而且这有一个很重要的含义:当我们在头文件中定义了const变量后,每个包含该头文件的源文件都有了自己的const变量,其名称和值都一样。PS:实践中,大部分的编译器在编译时都会用相应的常量表达式来替换对这些const变量的使用,即不会有任何存储空间用于存储该const变量。
如果const变量不是用常量表达式初始化,则不应该在头文件中定义,而应该和其它变量一样,在一个源文件中定义并初始化。在头文件中添加extern声明的话,则可以被多个文件共享。