第7章 程序组织结构
1 头文件
(1)头文件的作用是将程序文件中用到的函数等所在的程序包含进来,一块编译。将自己的程序函数定义、全局数据声明等放在头文件中,在其他程序文件中引用,可以避免自己将所有的函数、全局数据等在程序文件中声明。
(2)界面头文件
通过头文件可以明白的看出某个程序文件提供了什么服务,这种头文件成为界面头文件。
(3)头文件的内容可以是:
预编译指令
名空间定义,如:namespace N{ …}
类型声明和定义,如:enum COLOR{…}; class A{…};
模板声明和定义,如:template <class T> class A{…};
类声明,如:class A;
全局数据声明,如:extern int n;
全局常量定义,如:const float PI = 3.14;
函数声明
内联函数定义,如:inline void fn(){…};
注释。
(4)头文件一定不能包括的是:全局数据定义,函数定义。否则当头文件被多个程序文件包含时,造成函数或全局数据的重复定义。
2 全局数据
(1)全局数据是在函数外部声明或定义的,在整个程序范围内可以访问的数据。其作用于是整个程序范围,生命周期是整个程序运行时间。全局数据存储在全局数据区,在程序启时初始化为0.
(2)全局数据应该尽量少,因为它降低了模块间的独立性,增加了程序的复杂度。
(3)用参数传递的方式可以消除全局数据。
(4)全局数据必须遵守多次声明一次定义的原则。如果在不同的程序源文件中定义同名全局数据则会多次创建全局数据实体,则每个程序文件使用的是不同的实体。
(5)声明全局数据的形式是在定义前加extern.eg: extern int n. 如果是全局数据声明同时又写成初始化的形式,则只能是定义。Eg: extern int n = 7.是定义不是声明。
(6)全局常量
全局常量存储于全局数据区,可以在不同的源文件中重复定义,但在同一个源文件中只能定义一次。因其声明的时候必须初始化,故其本身就是定义。
3 静态全局数据
(1)静态全局数据以文件为划分单位,局部于文件。在文件内是可见的,在文件外不可见。以static标示。同样,局部于程序文件的函数称为静态全局函数。
(2)全局数据可以称为程序数据,静态全局数据可以称为文件数据,函数内的局部数据称为函数数据。
(3)没有静态全局常量,因为全局常量具有内部连接性(只在程序文件范围内有效),全局常量可以看作是文件常量(静态全局常量)。
4 静态局部数据
(1)静态局部数据存储在全局数据区,默认初始化值为0.
静态局部数据的可见性同局部变量相同,生命周期同全局变量,第一次被调用时创建,一直到程序运行结束。
(2)静态局部变量可以用来:a.确定函数是否被调用过,第二次进入和第一次进入函数的状态由于有了静态局变量而不同,b.确定函数被调用的次数。
(3)一般不要将静态局部变量的指针作为返回值。
5 作用域
C++的作用域包括:全局作用域、文件作用域、类作用域、函数作用域、函数原型作用域、局部作用域。
(1)函数作用域:不管名称在函数的什么地方,总是可以在函数的任何位置先用名称。只有标号是函数作用域。Goto 标号。
(2)函数原型作用域又称函数声明作用域。是表明函数声明时的形参与上下文无关。
Eg: void fun(Type arg1, Type arg2); arg1、arg2与上下文无关。
(3)局部作用域指函数内的语句块或整个函数范围内定义的数据应遵守的规则。
(4)在函数内,为防止全局变量被同名局部变量屏蔽,可以在全局变量前加名空间作用域操作符“::”,如果没有前缀,只有::加在名称前,则表示不属于任何名空间的全局名称。
(5)C++标准规范规定for循环中定义的循环变量的作用域为for循环语句块,但vc6.0不符合此规范,循环变量的作用域为包含for循环的语句块。
6 生命期
全局数据的生命周期是整个程序的运行时期。静态局部数据的生命期自函数被第一次调用起,到程序运行结束止。局部数据的生命期自局部数据被创建起,到函数调用结束止。
New、malloc后的实体生命期自申请到空间起,到delete、free止,其作用域为整个程序范围。
7 名空间
当程序规模很大时,仅用名称的作用域规则行不通,可以用名空间机制。一个名称必须在起使用域内明确规定其使用的名空间才能在域中默认地使用该名称。
名空间是跨文件的,作用域整个程序范围内,一般放在头文件中。
8 预编译
8.1 包含指令#include
对用引号包含的头文件编译器到用户的源程序文件路径中搜索,<>包含的头文件编译器到系统默认路径中搜索。
8.2 条件编译指令
其作用是取舍程序语句和协调多个头文件。#if…#elif…#endif, #ifdef…#ifndef…#endif.
8.3 头文件卫士
(1)其作用是保护嵌套的包含指令中的内部链接属性(只作用于文件)的名称不被重复定义,解决了单一定义规则。
#ifndef DATE
#define DATE
struct Date
{
Int year, month, day;
};
#endif
当该头文件因嵌套被多次包含进一个文件时,避免了Date类型在该文件中被重复定义。
(2)预编译名只在编译期存在,在调试和运行期不存在,不能与定义的类型名相同,为了在意义上相近,一般定义为类型名的全大写形式。
(3)外部链接(作用于整个程序)不允许在程序中被重复定义,不能放在头文件中;内部链接(作用于单个程序文件,如类型定义、枚举定义、全局常量定义、inline函数、模板定义等)可以跨文件重复定义,但在一个程序文件中只能被定义一次,可以包含在头文件中,为防止重复包含,可用头文件卫士。
8.4 宏定义#define
宏定义的函数类似于inline函数,不是真正的函数调用,而是在#define所定义的的名称处嵌入一段代码。
因为宏定义名称不能进入程序调试和运行,故尽量少用宏定义,改用const常量。
因宏定义的函数代换复杂,调试时显示展开后的代码,难以想象原代码的模样,故一般用inline函数,不用宏定义。