Download presentation
Presentation is loading. Please wait.
1
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构
2
第6章 C++程序的结构 学习目标 1. 区分各种变量的类型以及在内存中的存放; 2. 理解局部静态变量的双重特征;
第5章 构造数据类型 第6章 C++程序的结构 学习目标 1. 区分各种变量的类型以及在内存中的存放; 2. 理解局部静态变量的双重特征; 3. 区分各种类型标识符以及他们的作用域与可见性; 4. 掌握几种预处理命令的常用用途; 5. 理解名字空间的概念与几种使用方法。
3
C++语言程序设计教程 第5章 构造数据类型 6.1 变量的类型 除了按数据类型区分变量外,根据变量定义的位置,可以把变量分成全局变量与局部变量。全局变量是指定义在函数体外部的变量,它能被所有函数使用。局部变量是指定义在函数或复合语句中的变量,只能在函数或复合语句中使用。 int g=100000; int sum(int x, int y) { int sum=0; for(int i=x;i<=y;i++) sum=sum+i; return sum; } void main() int x=1,y=100; cout<<sum(x,y)+g<<endl; 1 2 3 4 5 6 7 8 9 10 11 12 13 g为全局变量 sum()中 x、y为局部变量 main()中的 x、y为局部变量
4
6.1.2 变量的存储类型 C++中变量有auto 、extern、register、static四种存储类型。 1.auto说明符
第5章 构造数据类型 6.1.2 变量的存储类型 C++中变量有auto 、extern、register、static四种存储类型。 1.auto说明符 auto说明符说明定义的是一个局部变量。局部变量默认存储类型为auto, 所以在程序中很少使用auto说明符说明。 2. register说明符 register说明符在定义变量时说明此变量存储在CPU中的寄存器中,以加快存取速度。一般编译器自己选择几个变量采用寄存器存储,不需要在程序中声明。 3. extern说明符 如果一个完整的计算机程序很大,分成多个模块,放在不同的文件中,分开编译成目标文件,最后连接成一个完整的可执行代码。对于所有模块共同使用的全局变量,如果在所有的模块中都定义,在连接时就会出错。 解决办法是只在一个模块中定义全局变量,在其他模块中用extern说明这是一个“外来”的全局变量。
5
运行结果: in p1 G=11 in p2 G=22 in p2 g=222 in p G=22 in p g=222
C++语言程序设计教程 第5章 构造数据类型 // p6_1_p1.cpp #include <iostream> using namespace std; extern int G; void p1dispG() { G=11; cout<<"in p1 G="<<G<<endl; } 1 2 3 4 5 6 7 8 9 /*************************** * p6_1_p.cpp * * 主程序 * ***************************/ #include <iostream> using namespace std; extern void p1dispG(); extern void p2dispG(); extern void p2dispg(); int G=0,g=0; void main() { p1dispG(); p2dispG(); p2dispg(); cout<<"in p G="<<G<<endl; cout<<"in p g="<<g<<endl; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // p6_1_p2.cpp #include <iostream> using namespace std; extern int G; extern int g; void p2dispG() { G=22; cout<<"in p2 G="<<G<<endl; } void p2dispg() g=222; cout<<"in p2 g="<<g<<endl; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 运行结果: in p1 G=11 in p2 G=22 in p2 g=222 in p G=22 in p g=222
6
6.1.2 变量的存储类型 static 数据类型 变量名=初值; 注意: 4. static说明符
第5章 构造数据类型 6.1.2 变量的存储类型 4. static说明符 static说明符用于在定义变量时将变量声明为成static(静态)变量。 其格式为: static可用来声明全局静态变量和局部静态变量。当声明全局静态变量时,全局静态变量只能供本模块使用,不能被其它模块再声明为extern变量。 例如:将程序p6_1_p.cpp中的全局变量声明为: static int G=0; 那么在其他模块中就不能声明为: extern int G; //错误,G已经是一个static变量; static 数据类型 变量名=初值; 注意: 当一个局部变量声明为static变量,它既具有局部变量的性质:只能在函数体局部存取;又具有全局变量的性质:函数多次进入,变量的值只初始化一次。因此静态局部变量实质是一个供函数局部存取的全局变量。
7
6.1.2 变量的存储类型 static型变量 运行结果: m=1 n=1 m=1 n=2 m=1 n=3 m=1 n=4
第5章 构造数据类型 6.1.2 变量的存储类型 /********************************** * 6_2.cpp * * 静态局部变量的使用 * **********************************/ #include<iostream> using namespace std; void fun() { static int n; int m=0; n++; m++; cout<<"m="<<m<<", n="<<n<<endl; } void main() for (int i=0;i<4;i++) fun(); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 static型变量 运行结果: m=1 n=1 m=1 n=2 m=1 n=3 m=1 n=4 静态局部变量n只是在函数fun()第一次进入时初始化0,随后每次进入不再赋初值
8
6.1.3 变量在内存中的存储 注意: ①全局数据区(data area) ②代码区(code area) ③栈区(stack area)
第5章 构造数据类型 6.1.3 变量在内存中的存储 当一个程序准备运行时,操作系统会为程序分配一块内存空间,C++程序的内存通常被分为四个区: ①全局数据区(data area) ②代码区(code area) ③栈区(stack area) ④堆区(heap area) 全局变量、静态变量、字符串常量、常变量存放在全局数据区;所有的函数和代码存放在代码区;为运行函数而分配的函数参数、局部变量、返回地址存放在栈区;堆区用于动态内存分配。 变量的生存期为从产生到消失的时期。全局变量、静态变量、常变量生存周期为整个程序的生存周期,因此称为静态生存期;局部变量的生存周期起于函数调用,结束于函数调用结束,其生存期是动态的,因此称为动态生存期。 注意: 堆空间不是系统为程序自动分配的,它是程序执行过程中由new语句为变量分配的。即使指向堆空间的指针变量消失,new语句分配的空间也不会消失。new语句分配的空间由delete语句释放。
9
C++语言程序设计教程 第5章 构造数据类型 6.1.3 变量在内存中的存储 /************************************** * p6_3.cpp * * 显示各类变量的内存分配 * ***************************************/ #include <iostream> using namespace std; int k=300; const int i=100; #define n 10 const int j=200; void fun(int i=1,int j=2) { int k=3; static int l=0; char *p=new char[n+1]; for(int m=0;m<n;m++) p[m]='A'+m; p[m]='\0'; cout<<"Adddress of parameter variable:"<<endl; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 常变量(常量)、全局变量、局部静态变量、字符串常量在程序运行前在数据区进行分配。并且依次按照常变量、全局变量、局部静态变量的顺序从低地址向高地址分配。常变量按定义的先后次序分配,全局变量、局部变量也一样。
10
6.1.2 变量的存储类型 运行结果: Adddress of parameter variable:
C++语言程序设计教程 第5章 构造数据类型 6.1.2 变量的存储类型 cout<<"&i="<<&i<<"\t"<<"&j="<<&j<<endl; cout<<"Adddress of local variable:"<<endl; cout<<"&k="<<&k<<"\t"<<"&p="<<&p<<"\t"<<"&m="<<&m<<endl; cout<<"Adddress of static local variable:"<<endl; cout<<"&l="<<&l<<endl; cout<<"Address of heap: "<<(void *)p<<endl; cout<<"before delete p="<<p<<endl; delete [] p; cout<<"after delete: "<<(void *)p<<endl; cout<<"p="<<p<<endl; } void main() { L1: fun(); L2: cout<<"Adddress of global variable:"<<endl; cout<<"&i="<<&i<<"\t"<<"&j="<<&j<<"\t"<<"&k="<<&k<<endl; cout<<"Address of function:"<<endl; cout<<"&fun="<<&fun<<"\t"<<"&main"<<&main<<endl; 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 运行结果: Adddress of parameter variable: &i=0013FF2C &j=0013FF30 Adddress of local variable: &k=0013FF20 &p=0013FF1C &m=0013FF18 Adddress of static local variable: &l= C Address of heap: //释放堆空间前指针的值 before delete p=ABCDEFGHIJ //释放堆空间前堆中的内容 after delete: //释放堆空间后指针的值不变 p=葺葺葺葺葺葺葺? //释放堆空间后,堆中的内容无意义 Adddress of global variable: &i=0046C01C &j=0046C020 &k=00474DC0 Address of function: &fun=004010A0 &main= F
11
6.1.2 变量的存储类型 解释 : 当函数被调用时才为函数的形参、返回代码地址、局部变量分配空间。由于空
C++语言程序设计教程 第5章 构造数据类型 解释 : 当函数被调用时才为函数的形参、返回代码地址、局部变量分配空间。由于空 间在栈中,所以从栈底开始依次按形参、返回代码地址、局部变量的顺序从 高地址向低地址分配。其中,在分配形参地址时,按从右向左的顺序;分配 各局部变量的地址时,按定义的先后次序。 当函数调用结束,该函数占用的栈空间收回。收回的顺序(即各变量消失的顺序 )与分配的顺序相反。 程序运行时,系统为各个函数的执行代码在代码段中分配空间,然后将代码调 入内存。各函数在代码区的排列次序按函数定义的先后次序。程序运行结束 ,程序占用的代码段空间收回。 常变量(常量)、全局变量、局部静态变量、字符串常量在程序运行前在数据区 进行分配。并且依次按照常变量、全局变量、局部静态变量的顺序从低地址 向高地址分配。常变量按定义的先后次序分配,全局变量、局部变量也一样。 当程序运行结束后,各全局变量的空间被系统收回,收回的顺序与分配的顺序 相同,即:先分配先收回。 堆空间不是系统为程序自动分配的,它是程序执行过程中由new语句为变量分 配的。即使指向堆空间的指针变量消失,new语句分配的空间也不会消失。 New语句分配的空间由delete语句释放。 变量的生存期为从产生到消失的时期。全局变量、静态变量、常变量生存周期 为整个程序的生存周期,因此称为静态生存期;局部变量的生存周期起于函数 调用,结束于函数调用结束,其生存期是动态的,因此称为动态生存期。 6.1.2 变量的存储类型
13
C++语言程序设计教程 第5章 构造数据类型 6.2 标识符的作用域与可见性 标识符的作用域是标识符在程序源代码中的有效范围,从小到大分为函数原型作用域、块作用域(局部作用域),文件作用域(全局作用域)。 1. 函数原型作用域 函数原型作用域是C++程序中最小作用域。函数原型声明时形式参数的作用范围就是函数原型的作用域。 例如:有下列函数声明: fun(int i, int j); 标识符i、j的作用域为函数原型,即函数fun形参的两个括号之间,在其他地方不能引用这些标识符。 2. 块作用域 所谓的块就是用{}括起来的一段程序,在块中定义的标识符,作用域从声明处开始,一直到块的大括号为止。其中有下列情况属于一个块: (1) 函数的形参与函数体属于一个块; (2) for()语句中,括号()中属于一个块;
14
6.2 标识符的作用域与可见性 /************************************** * p6_4.cpp *
{ i=4 i=5 i=3 i=2 } } C++语言程序设计教程 第5章 构造数据类型 6.2 标识符的作用域与可见性 /************************************** * p6_4.cpp * * 标识符作用域 * ***************************************/ #include <iostream> using namespace std; int i=100,j=200; void fun(int i=2) { cout<<"L2: i="<<i<<endl; int i=3; cout<<"L3: i="<<i<<endl; { for(int i=4;i<5;cout<<"L6:i="<<i<<endl,i++) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { {
15
6.2 标识符的作用域与可见性 运行结果: L2: i=2 L3: i=3 L4: i=4 L5: i=6 L6: i=4 {
C++语言程序设计教程 第5章 构造数据类型 6.2 标识符的作用域与可见性 { cout<<"L4: i="<<i<<endl; int i=5 i++; cout<<"L5: i="<<i<<endl; } void main() fun(); 16 17 18 19 20 21 22 23 24 25 26 27 28 运行结果: L2: i=2 L3: i=3 L4: i=4 L5: i=6 L6: i=4
16
6.2 标识符的作用域与可见性 4. 可见性 程序运行到某一处,能够引用到的标识符,称为该处可见到的标识符。可见性表示从某处能看到什么。
C++语言程序设计教程 第5章 构造数据类型 6.2 标识符的作用域与可见性 4. 可见性 程序运行到某一处,能够引用到的标识符,称为该处可见到的标识符。可见性表示从某处能看到什么。 可见性的一般规则是: (1) 块内层可以看到外层定义的各种标识符。 (2) 如果内、外层块定义的标识符同名,实质代表不同的实体,内层只能看到与 之最近的标识符,相当于外层标识符被内层同名的标识符隐藏了。 (3) 内层标识符的作用域不能覆盖(作用)到外层,所以外层看不到内层的标识符。 (4) 同层中,后面语句定义的标识符作用域不能作用到前面语句和块。因此,前 面语句看不到后面语句定义的标识符。 (5) 作用域作用的方向为从外向内、从前向后;可见性的方向则从内向外、从后 向前。
17
C++语言程序设计教程 第5章 构造数据类型 6.3 程序的文件结构与编译预处理命令 一个高级语言源程序在计算机上运行,必须先用编译程序将其翻译为机器语言。在编译之前还要做某些预处理工作,如去掉注释,变换格式等。 C++源程序中以#开头、以换行符结尾的行称为预处理命令。预处理命令不是C++语言的语法成分,在编译前由预处理器执行,在目标程序中,不含预处理指令对应的机器码。因此,预处理命令不以分号结尾。 许多预处理命令更适合C程序员,但为了处理C遗留的代码,C++编程者也应该熟悉预处理命令。
18
6.3 程序的文件结构与编译预处理命令 1. 文件包括 # include命令
第5章 构造数据类型 6.3 程序的文件结构与编译预处理命令 1. 文件包括 # include命令 文件包含是指在一个C++源程序中通过#include命令将另一个文件(通常是.h、.c或.cpp为后缀的文件)的全部内容包含进来。 文件包含处理命令的一般格式为: 编译时预编译器将被包含文件的内容插入到源程序中#include命令的位置,以形成新的源程序。 #include <被包含文件名> 或 #include "被包含文件名"
19
对主程序p6_5.cpp编译时预处理程序执行#include"mymath.h", 将p6_5.cpp变成:
第5章 构造数据类型 /***************************** * p6_5.cpp * * 主程序 * *****************************/ #include <iostream> using namespace std; #include "mymath.h" void main() { cout<<max(5,6)<<endl; } 1 2 3 4 5 6 7 8 9 10 //******************************* * mymath.h * * 一些自定义的数学函数 * ********************************/ #include <iostream> using namespace std; int max(int x,int y) { return x>y?x:y; } 1 2 3 4 5 6 7 8 9 10 对主程序p6_5.cpp编译时预处理程序执行#include"mymath.h", 将p6_5.cpp变成: #include <iostream> using namespace std; int max(int x,int y) { return x>y?x:y; } void main() { cout<<max(5,6)<<endl; 1 2 3 4 5 6 7 8 9 10 11
20
6.3 程序的文件结构与编译预处理命令 2. 不带参数的宏定义 宏定义分为两种:不带参数的宏定义和带参数的宏定义。
C++语言程序设计教程 第5章 构造数据类型 6.3 程序的文件结构与编译预处理命令 2. 不带参数的宏定义 宏定义分为两种:不带参数的宏定义和带参数的宏定义。 #define 命令定义一个标识符来代表一个字符串(表达式),在源程序中发现该标识符时,都用该字符串替换,以形成新的源程序。这种标识符称为宏名(macro name),将程序中出现的与宏名相同的标识符替换为字符串的过程称为宏替换或宏代换(macro substitulition)。 不带参数的宏定义的一般形式是: 其中: #define是宏定义命令名称。 标识符(宏名)被定义用来代表后面的单词串。 单词串是宏的内容文本,也称为宏体,可以是任意以回车换行结尾的文字。 单词串一般不用分号结尾。 #define 标识符 单词串
21
注意: 源程序 #include <iostream> using namespace std; #define SIZE 10
第5章 构造数据类型 源程序 #include <iostream> using namespace std; #define SIZE #define NEWLINE "\n" #define TAB "\t" void main() { int a[SIZE], i; for (i = 0; i < SIZE; i++) cout<<a[i]<<TAB; cout<<NEWLINE; } 1 2 3 4 5 6 7 8 9 10 11 12 预编译处理(宏替换)后的源程序 #include <iostream> using namespace std; #define SIZE #define NEWLINE "\n" #define TAB "\t" void main() { int a[ 10 ], i; for (i = 0; i < 10 ; i++) cout<<a[i]<< "\t"; cout<< "\n"; } 1 2 3 4 5 6 7 8 9 10 11 12 注意: 宏替换时仅仅是将源程序中与宏名相同的标识符替换成宏的内容文本,并不对宏的内容文本做任何处理。
22
6.3 程序的文件结构与编译预处理命令 #undef 标识符 宏定义时,要注意以下几点:
C++语言程序设计教程 第5章 构造数据类型 6.3 程序的文件结构与编译预处理命令 宏定义时,要注意以下几点: 程序员通常用大写字母来定义宏名,以便与变量名区别。这种习惯帮助读者迅速识别发生宏替换的位置。同时最好把所有宏定义放在文件的最前面或另一个单独的文件中,不要把宏定义分散在文件的多个位置。 宏定义时,如果单词串太长,需要写多行,可以在行尾使用反斜线\续行符。例如: #define LONG_STRING "this is a very long string that is\ used as an example" 双引号包括在替代的内容之内。 宏名的作用域是从#define定义之后直到该宏定义所在文件结束,但通常把#define宏定义放在源程序文件的开头部分。如果需要终止宏的作用域,可以使用#undef命令,其一般格式为: 宏定义可以嵌套定义、被重复定义, 但不能递归定义。 程序中字符串常量即双引号中的字符,不作为宏进行宏替换操作。 在定义宏时,如果宏是一个表达式,那么一定要将这个表达式用()括起来,否则可能会引起非预期的结果。 #undef 标识符
23
C++语言程序设计教程 第5章 构造数据类型 6.3 程序的文件结构与编译预处理命令 3. 带参数的宏定义 #define还有一个重要的功能:定义带参数的宏。这样的宏因为定义成一个函数调用的形式,也被称为类函数宏。在C++中由于可以使用函数模板,这种用宏定义的函数模板被取代。 带参数的宏定义的一般形式为 参数表由一个或多个参数构成,参数只有参数名,没有数据类型符,参数之间用逗号隔开,参数名必须是合法的标识符。参数列表类似函数的形参表。 预编译器首先将实参按参数列表中参数对应的顺序,取代内容文本中的参数;再将这个宏的实际内容文本替换源程序中的宏标识符: #define 标识符(参数列表) 单词串
24
C++语言程序设计教程 第5章 构造数据类型 源程序 #define MAX(x,y) ( ( (x) > (y) ) ? (x) : (y) ) void main() { float a = -2.5, b = -3.2; cout<<MAX(a,b)<<endl; } 1 2 3 4 5 6 预编译处理(宏替换)后的新源程序 void main() { float a = 2.5, b = -3.2; cout<< ( ( (a) > (b) ) ? (a) : (b) )<<endl; } 1 2 3 4 5 6 说明: 预编译器在处理上面源程序中的MAX(a,b)时,首先将MAX(x,y)的宏内容文本中的x替换成a,将y替换成b,形成新的宏内容是:( ( (a) > (b) ) ? (a) : (b) ),然后将MAX(a,b)替换成( ( (a) > (b) ) ? (a) : (b) )。
25
C++语言程序设计教程 第5章 构造数据类型 6.3 程序的文件结构与编译预处理命令 4. 条件编译 一般情况下,源程序中所有的语句都参加编译,但有时也希望根据一定的条件去编译源文件的不同部分,这就是条件编译。条件编译使得同一源程序在不同的编译条件下得到不同的目标代码。 条件编译有几种常用的形式,现分别介绍如下: (1) #if ~ #endif形式 #if ~ #endif形式的条件编译的格式为: 其中: elif是else if的缩写,但不可写成else if。 #elif和#else可以省略,但#endif不能省略,它是#if命令的结尾。 #elif命令可以有多个。 if后面的条件必须是一个常量表达式,通常会用到宏名,条件可以不加括号() #if 条件1 程序段1 #elif 条件2 程序段2 ... #else 程序段n #endif
26
注意: #if和#elif常常与defined命令配合使用
C++语言程序设计教程 第5章 构造数据类型 源程序 #define USA #define CHINA #define ENGLAND 2 #define ACTIVE_COUNTRY USA #if ACTIVE_COUNTRY = = USA char *currency = "dollar"; #elif ACTIVE_COUNTRY = = ENGLAND char *currency = "pound"; #else char *currency = "yuan"; #endif void main ( ) { float money; cin>>money; cout<<money<<currency<<endl; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 预编译处理后的新源程序 char *currency = "dollar"; void main ( ) { float money; cin>>money; cout<<money<<currency<<endl; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 注意: #if和#elif常常与defined命令配合使用
27
6.3 程序的文件结构与编译预处理命令 (2) #ifdef ~ #endif #ifdef ~ #endif形式的条件编译的格式为:
C++语言程序设计教程 第5章 构造数据类型 6.3 程序的文件结构与编译预处理命令 (2) #ifdef ~ #endif #ifdef ~ #endif形式的条件编译的格式为: 其中: #else可以省略,#endif不能省略,它是#if命令的结尾。 在#ifdef和#else之间可以加多个#elif命令。 “#ifdef 宏名”的含义是判断是否定义了宏,它等价于“#if defined(宏名)”。 其作用是:如果宏名已被#define行定义,则编译程序段1,否则编译程序段2。 #ifdef 宏名 程序段1 #else 程序段2 #endif
28
6.3 程序的文件结构与编译预处理命令 (3) #ifndef ~ #endif #ifndef ~ #endif形式的条件编译的格式为:
C++语言程序设计教程 第5章 构造数据类型 6.3 程序的文件结构与编译预处理命令 (3) #ifndef ~ #endif #ifndef ~ #endif形式的条件编译的格式为: 条件编译呢主要用于下列几种场合: (1) 避免重复包含引起变量函数的重复定义引起的冲突。如果某个程序的头文件中已定义了某个常量,用条件编译进行判断后,就不再重新定义该常量,避免造成不一致;如果在头文件中如果包含某个模块,用条件编译进行判断后,就可不再重复包含此模块,避免变量、函数重名冲突。 #ifndef 宏名 程序段1 #else 程序段2 #endif 注意: 与第2种形式的区别仅在于:如果宏名没有被#define定义,则编译程序段1,否则编译程序段2。
29
源程序 C++语言程序设计教程 预编译处理后的新源程序 第5章 构造数据类型 1 #include <iostream> 2
/*************************** * mymath.h * ****************************/ #include <iostream> using namespace std; #define INTMAX int max(int x,int y) { return x>y?x:y; } /*********************** * 主程序 * ***********************/ #include "mymath.h" #ifndef INTMAX #endif void main() cout<<max(5,6)<<endl; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 预编译处理后的新源程序 #include <iostream> using namespace std; #include <iostream> #define INTMAX int max(int x,int y) { return x>y?x:y; } void main() cout<<max(5,6)<<endl; 解释:主程序中定义的int max(int,int)在预处理时被过滤掉,没有进入编译,避免了与mymath.h中的 int max(int,int)冲突。 1 2 3 4 5 6 7 8 9 10 11 12 13
30
C++语言程序设计教程 第5章 构造数据类型 6.3 程序的文件结构与编译预处理命令 (2) 便于程序的移植。 如在PC机上,最常用的C++有BC++、VC++、Linux GNU C++,三者在实现上有一些不同之处,如果我们希望自己的源程序能够适应这种差异,可以在有差异的地方插入选择判断: #ifdef VC++ … //visual C++独有的内容 #endif #ifdef BC++ … //Borland C++独有的内容 #ifdef GC++ … //Linux Gnu C++独有的内容 如果希望这个程序在Borland C++环境下编译运行,可在程序的前面写上: #define BC++ 这样一个源程序只要修改一句就可以适应三种C编译,商业软件经常就是这样编写的。再比方说商业软件的版本中经常出现的单机版、网络版,其实网络版只是在单机版的基础上增加了相应的一些网络功能,功能上大体相同,所以在同一软件程序中将单机版的功能和网络版的功能通过条件编译就可得到相应的版本。
31
C++语言程序设计教程 第5章 构造数据类型 6.4 名字空间 一个软件往往由多个模块(组件)组成,这些模块由不同程序员(软件商)提供,不同模块可能使用了相同的标识符。简单说就是同一个名字在不同模块中代表不同的事物。当这些模块用到同一个程序中,同名标识符就引起冲突。C++提供名字空间(namespace) 将相同的名字放在不同空间中来防止命名冲突。 定义一个名字空间的格式如下: 其中: namespace 为关键字。 名称为名字空间标识符。 成员为函数、变量、常量、自定义类型等。 namespace 名称 { 成员; }
32
6.4 名字空间 例如: 一个名为TsingHua的软件公司为自己的组件建立了一个名字空间。将它存入头文件:TsingHua.h
C++语言程序设计教程 第5章 构造数据类型 6.4 名字空间 例如: 一个名为TsingHua的软件公司为自己的组件建立了一个名字空间。将它存入头文件:TsingHua.h /*************TsingHua.h**********/ namespace TsingHua { int year=2005; char name[]="TsingHua Software"; ShowName() cout<<name<<endl; }
33
6.4 名字空间 (1)个别使用声明方式,格式如下: 其中: ::为作用域分辨符。 成员使用形式包括函数调用式、变量名、常量名、类型名等
C++语言程序设计教程 第5章 构造数据类型 6.4 名字空间 (1)个别使用声明方式,格式如下: 其中: ::为作用域分辨符。 成员使用形式包括函数调用式、变量名、常量名、类型名等 名字空间名::成员使用形式 /***************************** * p6_6.cpp * * 名字空间的使用 * *****************************/ #include <iostream> using namespace std; #include "TsingHua.h" void main() { TsingHua::ShowName();//个别声明方式 } 1 2 3 4 5 6 7 8 9 10 11
34
6.4 名字空间 (2)全局声明方式: 这种方式表明此后使用的成员来自于声明处的名字空间,程序p6_6.cpp中第6行:
第5章 构造数据类型 6.4 名字空间 (2)全局声明方式: 这种方式表明此后使用的成员来自于声明处的名字空间,程序p6_6.cpp中第6行: using namespace std; 表明此后使用的名字空间为C++标准库名字空间std,此后的cout、endl均来自名字空间std。 (3) 全局声明个别成员: 这种声明形式表明以后使用的成员M来自名字空间N。成员名M为函数、变量、常量、类型的名字。 using namespace名字空间名 using 名字空间名N::成员名M
35
6.4 名字空间 /***************************** * p6_7.cpp * * 名字空间的使用 *
第5章 构造数据类型 6.4 名字空间 /***************************** * p6_7.cpp * * 名字空间的使用 * *****************************/ #include <iostream> using std::cout; //后面的cout来自名字空间std using std::endl; //后面的endl来自名字空间std #include "TsingHua.h" void main() { using TsingHua::ShowName; //后面的showName()来自名字空间TsingHua ShowName(); } 1 2 3 4 5 6 7 8 9 10 11 12 13 说明: 通常,将全局声明方式与个别使用声明方式以及全局声明个别成员方式相结合使用。使用系统提供的名字空间成员采用全局声明方式,使用自己定义名字空间的成员采用个别使用声明方式或全局声明个别成员方式。
36
C++语言程序设计教程 第5章 构造数据类型 本章小结 ◇ 全局变量是指定义在函数体外部的变量,它能被所有函数使用。局部变量是指 定义在函数或复合语句中的变量,只能在函数或复合语句中使用。 ◇当一个局部变量声明为static变量,它既具有局部变量的性质:只能在函数体 局部存取;又具有全局变量的性质:函数多次进入,变量的值只初始化一次。 因此静态局部变量实质是一个供函数局部存取的全局变量。 ◇C++程序的内存被分为四个区:全局数据区,代码区,栈区,堆区。 ◇全局变量、静态变量、字符串常量、常变量存放在全局数据区; 所有的函数和 代码存放在代码区; 为运行函数而分配的函数参数、局部auto变量、返回地址 存放在栈区。堆区用于动态内存分配。 ◇全局变量、静态变量、常变量生存周期为整个程序的生存周期,因此称为静态 生存期;局部auto变量的生存周期起于函数调用,结束于函数调用结束,其生 存期是动态的,因此称为动态生存期。 ◇标识符的作用域从小到大依次为:函数原型作用域,块作用域,文件作用域。 ◇C++源程序中以#开头、以换行符结尾的行称为预处理命令。预处理命令在编译 前由预处理器执行。 ◇C++提供名字空间(namespace) 将相同的名字放在不同空间中来防止命名冲突。 可以通过三种方法使用名字空间,个别使用声明方式,全局声明方式,全局声 明个别成员方式。
Similar presentations