C++基础

1,415 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,415
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

C++基础

  1. 1. 1 基本概念1.1 面向对象的程序设计思想面向对象程序设计的本质是把数据和处理数据的过程当成一个整体对象。 C++ 充分支持面向对象的程序设计。面向对象 程序设计的实现需要封装和数据隐藏技术,需要继承和多态技术。(1)封装和数据隐藏: C++ 通过建立用户定义类型(类)支持封装性和数据隐藏。完好定义的类一旦建立,就可以看成是完全封装的实体,可以作为一个整体单元使用。类的实际内部工作应当隐藏起来,使用完好定义的类的用户不需要知道类是如何工作的,只要知道如何使用它就行。(2)继承和重用: C++ 采用继承支持重用的思想,程序可以在扩展现有类型的基础上,声明新类型。新子类是从现有类型派生来的,称为派生类。(3)多态性:
  2. 2. 通过继承的方法构造类,采用多态性为每个类指定表现行为。继承性和多态的组合,可以轻易地生成一系列虽类似但独一无二的对象。由于继承性,这些对象共享许多相似的特性。但由于多态性,一个对西哪个可以有独特的表现方式,而对另一个对象有另一种表现方式。1.2 面向对象的程序设计过程面向对象的程序设计,在后面的章节中,均以 OOP 表示面向对象的程序过程大体上分为三个过程:即面向对象的分析( OOA )、面向对象的设计( OOD )、面向对象的实现( OOP )。1、面向对象的分析:面向对象的分析的主要作用是明确用户的需求,并用标准化的面向对象的模型规范地表述这一需求,最后将形成面向兑现的分析模型,即 OOA 模型。该阶段应该由开发人员和用户协同完成,这种 OOA 模型包含五个层次,每个层次描述需求模型的一个方面。•对象-类层:这个层次将捕捉要开发的应用软件所对应的各个显示世界的试题,并从中抽象出对象和类。•静态属性层:
  3. 3. 该层将为对象-类层中抽取出来的各个类和对象设计静态属性(状态)和它们之间的约束关系。服务层:该层定义了对象和类的动态属性以及对象之间的消息通信。对象和类的动态属性就是它们的行为或方法(由称为服务),它规定了对象和类的作用和功能,当对象在执行这些功能时,它们之间将引发消息通信。•结构层:该层将定义系统中所有对象和类之间的层次结构关系。如包含、继承、关联等关系。•主题层:主题层将定义若干个主题,把有关的主题层分别划归不同的主题,每个主题成为一个子系统。2、面向对象的设计:面向对象的设计将在 OOA 模型的基础上引入界面管理、任务管理和数据管理三个部分的内容。其中界面管理负责整个系统的人机界面的设计;任务管理负责处理并行操作之类的系统资源管理功能的工作;数据管理则负责设计系统与数据库的接口。在这个过程中,应充分利用已经存在的、可获得的对象类或不见。这样做可以大大提高开发效率和可靠性,降低开发成本。另外还要考虑将可重用的部件优先开发出来,对整个开发任务也将是非常关键的。
  4. 4. 3、面向对象的实现:面向对象的实现就是具体的编码阶段,主要工作是:•选择一种合适的面向对象的变成语言,如 C++ 、 Java 等。•用选顶的语言编码实现详细设计步骤所的的公式、图表、说明和规则等对软件系统个对象类的详尽描述。•将编写好的各个类代码模块根据类的相互关系集成。•作好测试工作。1.3 C++ 程序的开发过程程序员开发 C++ 程序的过程通常由四步组成,即编辑、编译、连接、运行。程序员首先在集成开发环境中编辑源程序,或者在其他编辑器中输入源程序,然后在集成开发环境汇总启动编译程序( compile )编译后,生成一个目标文件,这个文件通常以 .obj 为文件扩展名,该目标文件为源程序的目标代码,即机器语言程序。最后由连接程序( link )将目标程序连接后,形成可执行程序( .exe )。整个开发过程如下所示:
  5. 5. 4.1 函数的定义与函数原型在编制应用程序的过程中,为了便于开发和管理程序,让多个人同时工作,提高编程效率,通常把一个大的程序划分为若干个模块,每个人只需要关注在自己的程序上,而不受其他人的干扰,当需要别的模块时,只需要知道那个模块的接口部分就可以使用了,而不需要知道那个模块实现的细节。这种模块化的设计思想在 C++ 中是以函数来实现的。函数是 C++ 的基本特征。它封装了一些程序代码和数据,实现了更高层次的抽象,在 C++ 编程中,常常把一个程序分成多个函数来实现。函数抽象的实现,有利于数据共享,节省开发时间,增强程序的可靠性和便于管理等。可以说, C++ 的程序实际上就是函数的聚集。在基于控制台的应用程序开发中,有一个重要的函数,即 main() 函数,它是个特殊的函数,它是程序执行的入口,每个 C++ 程序都必须有且仅有一个 main() 函数。
  6. 6. •函数的定义格式:<返回类型><函数名> (<参数表>){函数体}其中:①<返回类型>是该函数的返回值类型。它可以是各种数据类型。当函数没有返回值时,该函数的类型为空,用 void 表示无返回值的函数类型。②<参数表>可以无参数,有一个参数,有多个参数。当无参数时,只用 () 来表示就行了。③当函数返回值时,在函数体内用 return <表达式>来返回。例 1 :intsum_int(intx,int y){
  7. 7. returnx+y;}例 2 : void message(){cout<<”this is a messagen”;}•函数原型函数原型又称为函数声明。和变量在使用之前必须先定义相似,函数在使用之前也必须先定义或声明。在 C++ 中,函数的声明原则如下:如果一个函数定义在先,调用在后,调用前可以不必声明;如果一个函数定义在后,调用在先,调用前必须声明。根据这个原则,凡是被调用函数都在调用函数之前定义时,可以对函数不加声明。但是,这样做要在程序中安排函数的顺序上费一些精力,在复杂的调用中,一定要考虑好谁先谁后,否则将发生错误。因此,避免确定函数定义的顺序,并且使得程序设计上逻辑结构的清楚,常常将主函数放在程序头,这样就需要对被调用的函数进行说明。
  8. 8. 格式:<函数类型><函数名> (<参数表>);•函数的调用调用格式:<函数名>(<实在参数表>)其中,<实在参数表>是由 0 个、 1 个或多个实在参数组成,多个参数用逗号分隔,每个参数是一个表达式。实在参数的个数由形参决定,实参是用来在调用函数时给形参初始化的。因此,要求在函数调用时,实参的个数和类型要与形参的个数和类型是一致的,即个数相等,类型相同。实参对形参初始化是按其位置对应进行,即第一个实参的值赋给第一个参数,第二个实参的值赋给第二个形参,依此类推。函数调用是一种表达式,函数调用表达式的值是函数的返回值,其类型为函数类型。函数值可以赋给某个变量,以改变变量的值或给变量赋值。返回语句有两种格式,一种为:return <表达式>;
  9. 9. 另一种:return; 其执行过程是:先计算表达式的值,如果表达式的类型与与函数的类型不相同,将表达式的类型自动转换为函数的类型,然后将计算的表达式的结果调用函数,作为函数的值,该值可以赋给某变量,也可以输出显示。最后将程序的控制权由被调用函数转向调用函数,执行调用函数后面的语句。当函数无返回值时,只返回程序的控制权。•函数的传值调用函数调用方式在 C++ 中除了传值调用之外,还有引用调用。由于在 C++ 中变量值有两种:变量本身的值和变量的地址值。传值调用也分为两种:一种是传递变量本身的值的称为传值调用,另一种是传递变量地址值的称为传址调用。使用传值调用方式时,调用函数的实参用常量、变量值或表达式值,被调用函数的形参用变量。调用时,系统先计算实参表达式的侄,再将实参的值按位置对应赋给形参,即对形参初始化。传值调用的机制是系统将实参拷贝一个副本给形参。在被调用函数中,形参可以被改变,实参不能被改变。因此,传值调用的特点是:形参的值的改变不影响实参。
  10. 10. 例1:阅读下列程序,输出程序结果。#include<iostream.h>void swap(int,int);void main(){int a=5,b=6;cout<<”a=”<<a<<” “<<”b=”<<b<<endl;swap(a,b);cout<<”a=”<<a<<” “<<”b=”<<b<<endl;}void swap(intx,int y){int temp;
  11. 11. temp=x;x=y;y=temp;cout<<”x=”<<x<” “<<”y=”<<y<<endl;}程序的执行结果:a=5 b=6x=6 y=5a=5 b=6从该程序中看到,在 swap() 函数中对 x 和 y 这两个形参做了一次交换。但在 main() 函数中实参 a 和 b 的值还是原来的值,可见在 swap() 函数的形参值的改变,对实参 a 和 b 没影响。如果想让形参的改变影响实参,应选用传址调用和引用调用。传址调用要用到指针,而引用调用要用到引用,在后面章节再仔细介绍。
  12. 12. 4、函数的参数的求值顺序当一个函数带有多个参数时, C++ 语言没有规定在函数调用时实参的顺序。而编译器根据对代码进行优化的需要自行规定对实参的求值顺序。Visulal C++ 编译器按照从左到右的顺序。⑴设置函数参数的默认值默认参数也称缺省参数。 C++ 可以给函数定义默认参数值。例如: void delay(int loop=1000);这是一个函数声明,在声明中为参数 loop 赋默认值 1000 ,则在调用该函数时,参数可以缺省,编译器会取默认值 1000, 也可以带实参调用,编译器会取实参的值。注意只能在函数声明中为参数指定默认值,不能在函数调用时为参数指定默认值。例2:一个设置默认的参数值的函数的例子。#include<iostream.h>void fun(int a=1,int b=3,int c=5);void main(){
  13. 13. fun();fun(7);fun(7,9);fun(7,9,12);cout<<”right!”<<endl;}void fun(inta,intb,int c){cout<<”a=”<<a<<”,”<<”b=”<<b<<”,”<<”c=”<<c<<endl;}执行该程序,输出结果:a=1,b=3,c=5
  14. 14. a=7,b=3,c=5a=7,b=9,c=12该程序中的函数的定义头时设置了参数的默认值,而在调用函数时,有的无实参,有的实参数目不足,有的实参数目与形参性同,分若干不同情况来说明默认值的使用。5、几点注意:⑴默认参数在函数声明中提供,当又有声明又有定义时,定义中不允许默认参数。当函数只有定义时,则默认参数才可出现在函数定义中。⑵在 C++ 语言中对于函数的参数,如果指定了默认参数的值,则其右边不能再出现没有指定默认值的参数。例如: void fun(int a=1,int b,int c); //errorvoid fun(inta,intb,int c=4); //ok⑶在对带默认参数的函数调用时,可能出现二义性。例如: void fun(int);void fun(int,int =3);
  15. 15. void fun(int =1,int =3);调用该函数时, fun(7) 到底调用的是哪一个呢?这时就引起了调用的二义性。⑷默认参数可以将一系列简单的重载函数合成为一个,从而优化编程。例如: void para(int a=1,int b=2,int c=3);调用时,可以带一个参数 para(1) ,可以带两个参数 para(2,4) ,可以带三个参数para(10,20,30) 。也可以不带参数 para() 。这样可以消除简单的函数重载。⑸参数的默认值可以是全局变量、全局常量,甚至可以是一个函数。4.2 函数的调用机制 C++ 的函数调用过程,就是栈空间操作的过程。栈是一种数据结构,这种数据结构遵循一个原则:先进后出。即先进栈的数据后出,而后进栈的数据先出。函数调用实际上是进行程序的跳转,在转去执行函数之前,应把现场保护起来,以备函数执行完毕还回到刚才跳转的地方,接着执行后继程序。所以函数调用时, C++ 会做保护现场的工作:⑴建立被调函数的栈空间。
  16. 16. ⑵保护调用函数的运行状态和返回地址。⑶传递参数。⑷将控制权转交被调用函数。例3:下面的代码在主函数中调用一个函数。该函数又调用了另一个函数,它得到的内存布局如图 4-1 所是示void func1(int ,int );void func2(int);void main(){int a=6,b=12;func1(a,b);}void func1(intaa,int bb)
  17. 17. {int n=5;func2(n);}void func2(int s){int x=10;}该程序调用机制中的栈结构如下:栈区
  18. 18. xfunc2() s105返回地址调用函数运行状态nfunc1() bbaa512
  19. 19. 6返回地址调用函数运行状态bamain()126参数返回地址操作系统运行状态
  20. 20. 当主函数调用 func1() 时, func1() 着手保护户调用函数的地址等数据,分配两个形参的空间,将主函数的实参传递过来。则 func1() 中的两个形参分别为 6 和 12 。 Func1() 的栈区和 main() 的栈区是互相独立的。在 func1() 中不能访问 main() 中的局部变量 a和 b 。通过参数传递,使得 func1() 中的形参赋有 main() 函数中的实参值。 Func1() 可以修改其变量 aa 和 bb ,但是始终不能影响 main() 中的 a 和 b 。这也是 C++ 中的传值特性。在函数 func1() 中,定义了一个局部变量 n, 并一该变量作为实参调用函数 func2() 。同样,func2() 建立了自己的栈空间,保护 func1() 的返回地址,获得参数值,随后运行它自己的函数体语句。当 func2() 执行完毕,将从栈中将 func1() 的返回地址弹出,接着执行 func1() 的其他语句,当func1() 执行完毕,又从栈中返回 main() 的返回地址,接着执行 main() 中的其他语句。 Main() 函数执行完毕,返回系统地址。这个应用程序就这样执行完毕。栈在系统中不是用之不竭的资源,每次调用一个函数,所建立的栈空间都比上一个函数的栈空间要小。所以一层一层的调用,会出现栈空间不够的情况,这就会出现栈溢出的问题。解决的方法,是在连接之前通过设置栈空间的大小来改善栈空间有限的局限。4.3 内联函数、递归函数和函数重载 1、内联函数内联函数也称内嵌函数。引入内联函数的目的是为了解决程序中函数调用的效率问题。前面我们讲过,函数的引入使得编程者只关心函数的功能和使用方法,而不必关心函数功能的具体实现;另外,函数的引入可以减少程序的代码,实现程序代码和数据的共享。但是函数调用也会带来降低效率的问题,因为调用函数实际上将程序执行顺序转移到函数所存放的内存地址处,将函
  21. 21. 数的程序执行完毕,再返回到转去执行程序前的地方。这种转移操作要求在转去前保护现场并记忆执行的地址,转回后先要恢复现场,并按原来的保护地址继续执行。因此函数调用是以牺牲时间和空间为代价的。对于一些函数体代码不是很大,但又频繁地被调用的函数来讲,解决其效率问题更为重要。这是引入内联函数的初衷。在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换。这种做法不会出现程序转向的问题,但是这样会增加程序的代码量,进而增加空间开销,可见内联函数是以目标代码的增加为代价来换取时间的节省。⑴内联函数的定义方法定义内联函数的方法很简单,只要在函数定义的的头前加上关键字 inline 即可。内联函数的定义方法和普通函数的定义方法相同。例如: inline int add(intx,int y){returnx+y;}例4:编程求 1~100 之间的数的立方。#include<iostream.h>
  22. 22. inlineint curb(int x){return x*x*x;}void main(){for(int I=1;I<=100;I++)cout<<I<<”*”<<I<<”*”<<I<<curb(i)<<endl;}该程序中,函数 curb() 是内联函数,该函数在编译时被其代码替代,而不象普通函数那样是在运行时被调用。⑵几点注意:•在内联函数中不允许用循环语句和开关语句。
  23. 23. •内联函数的定义必须出现在内联函数第一次被调用前。•后面讲到的类结构中的所有在类说明内部定义的函数都是内联函数。•内联函数只适合于一到五行的小程序,对于含有许多语句的大函数,函数调用和返回时的开销相对来说微不足道,没有必要用内联函数。2、递归调用在一个函数体中可以调用另一个函数,当被调用函数是这个函数自身或者被调函数中又调用这个函数时,这种调用就是递归调用。前者为直接递归调用,后者称为间接递归调用。例如,在 f1()函数体内,又调用了 f1() ,或着在函数 f1() 中,调用了 f2() ,而在 f2() 中又调用了 f1(), 着两种情况都属于递归调用。•递归调用机制:⑴任何函数之间不能嵌套定义,调用函数与别调用函数之间相互独立。⑵发生函数调用时,被调用函数中保护了调用函数的运行环境和返回地址,使得调用函数的状态可以在被调用函数返回后完全恢复,而且该状态与被调用函数无关。⑶被调用函数栈空间独立于调用函数的栈空间,所以与调用函数之间的数据也是无关的。函数之间靠参数传递和返回值来联系。这种机制决定了 C++ 允许函数递归调用。
  24. 24. •递归的条件⑴须有完成函数任务的语句。⑵应有一个条件语句,用以判定递归调用的条件。这是必须的。⑶有一个递归调用语句。该递归调用语句的参数逐渐逼近不满足条件,以至最后断绝递归。⑷递归语句应该放在条件语句体中。也就是说递归调用前必须先测试。例5:编程计算某个正整数的阶乘。#include<iostream.h>longintfac(int n);void main(){int n;
  25. 25. cin>>n;long f=fac(n);cout<<n<<”!”<<f<<endl;}longintfac(int n){longint p;if(n==0) p=1;elsep=n*fac(n-1);return p;}
  26. 26. 例6:以下函数 poly 是用递归方法计算 x 的 n 阶勒让德多项式的值。已有调用语句“ p(n,x)”; 编写poly 函数。递归公式如下:poly n (x)=1 当 n=0 时;poly n (x)=x 当 n=1 时 ;poly n (x)=((2n-1)*x*poly n-1 (x)-(n-1)*poly n-2 (x))/n 当 n>1 时程序如下:#include <iostream.h>double p(intn,double x);void main(){int m;double xx;
  27. 27. cin>>m>>xx;cout<<p(m,xx);}double p(intn,double x){if(n==0)return 1;else if(n==1)return x;elsereturn ((2*n-1)**p(n-1,x)-(n-1)*p(n-2,x))/n;}
  28. 28. •递归调用的优点⑴简化程序设计⑵使程序可读•递归调用的缺点递归增加了系统的开销。时间上,执行调用与返回的额外工作要占用 cpu 时间。空间上,随着每递归一次,栈内存就多占用一些。3、函数重载所谓函数重载是指同一个函数名可以对应着多个函数的实现。这样做可以提高程序的可读性,但是那么多的同名函数,在进行实际调用的时候怎么知道调用的是哪一段代码呢?编译器是用函数名加参数的方法来区别函数,就是说,确定函数实现时,要求从函数参数的个数和类型上来区别,这就要求通明函数在参数个数上不同,或者参数类型不同。否则将无法实现函数重载。例7:求两个操作数之差。#include<iostream.h>intminue(int,int);
  29. 29. doubleminue(double,double);void main(){cout<<minue(12,2)<<endl;cout<<minue(12.5,4.6)<<endl;}intminue(intx,int y);{return x-y;}doubleminue(double x,bouble y){return x-y;
  30. 30. }该程序中, main() 函数调用了相同名字 minue 的两个函数,前边一个 minue() 函数对应的是两个 int 型数的差的函数的实现,而后边一个 minue() 函数对应的是两个 double 型数差的函数实现,这就是函数的重载。•几点注意:⑴重载函数不能仅仅是返回类型不同,还必须在参数类型、参数个数和参数顺序上有所不同。例如,下面的声明有问题:void f(double);double f(double);编译器无法区分函数调用 f(3.5) 是指上述哪个重载函数。⑵不能用 typedef 定义的类型名来区分重载函数声明中的参数。因为用 typedef 定义的类型只是已有类型的别名而已。⑶重载函数描述的应该是相同功能,而只是数据类型不同的代码,否则会影响程序的可读性。
  31. 31. ⑷当一个函数调用找不到严格相匹配的重载函数时,会将参数进行类型转化,寻求其他匹配。但这时容易出现二义性。如: void print( long);void print(double);函数调用 print(3) 可以转化为 long 型,也可以转化为 double ,这时就分辨不出该和哪个函数匹配了。从而出现二义性。 例8:编写一个包含三个重载函数的程序,重载函数名为 display() 。第一个函数输出一个double 型值,前面用字符串”A double:”引导;第二个函数输出一个 int 值,前面用字符串”A int:”引导;第三个函数输出 char 字符,前面用字符串”A char:”引导。在主函数中,分别用double,float,char 和 short 型变量去调用 display() 函数,并对结果做简要说明。程序如下:#include <iostream.h>void display(double);void display(int);void display(char);
  32. 32. void main(){display(12.5);display(12);display(‘A);display((short)12);}void display(double a){cout<<” A double:”<<a<<endl;}void display(int a){
  33. 33. cout<<” A int :”<<a<<endl;}void display(char a);{cout<<” A char :”<<a<<endl;}程序运行结果:A int:12A double:12.5A char: A第一行的结果调用了 void display(int), 第二行输出和 void display(double) 匹配,第三行输出和void display(char) 匹配。例9:分析下列程序的运行结果:
  34. 34. #include<iostream.h>voidff(int);voidff(double);void main(){float a=88.7;ff(a);char b=a;ff(b);}voidff(int x){
  35. 35. cout<<”ff(int):”<<x<<endl;}voidff(double x){cout<”ff(double):”<<x<<endl;}运行结果为:ff(double):88.7ff(int):97这里,函数调用 ff(b) 中的参数 b 是字符型的,找不到严格的匹配,就将 char 型转换为 int 型,与 ff(int) 匹配,结果是字符 a 的 ASC Ⅱ码。4.4 变量的划分和作用域1、作用域作用域又称作范围。在程序中出现的各种标识符,它们的作用域是不同的。
  36. 36. ⑴标识符的作用域规则:•大多数的标识符对它说明和对它定义是一回事。只有少数的标识符对它说明和对它定义是两回事。例如:外部变量、函数和类等。•标识符包含了常量名、变量名、函数名、类名、对象名、语句标号等等。凡是使用标识符规则定义的各种单词都属于标识符。•可见的是指可以进行存取和访问的,不可见的是指不可以进行存取和访问的。•作用域有大有小,最大的是整个程序,最小的是块,中间的有文件和函数,每当定义标识符时是在一定范围内定义的。•在相同的作用域内不能出现相同的变量名,但在不同的作用域内可以存在相同的变量名。⑵作用域的种类:不同的标识符定义在不同的范围内有着不同的作用域。按作用域的大小不同可以分为:•程序级:其作用域最大,包含着组成该程序的所有文件。属于程序级作用域的有外部函数和外部变量。这类标识符是在某个文件中定义的,在该程序的其他文件中都是可见的,一般地在访问之前需要加以说明。
  37. 37. •文件级:属于文件作用域的有内部函数和外部景泰变量。这种作用域是仅在定义它的文件内。对外部静态变量来讲,作用域是从定义时起,到该文件结束为止。另外,用宏定义所定义的符号长俩一般是属于文件级的。•函数级:属于函数级作用域的有函数的形参、函数体内定义的局部变量和内部静态变量以及函数中的标号。•块级:属于块级作用域的有定义在分程序中、 if 语句中、 switch 语句中以及循环语句中的 auto型变量和内部静态变量。•文件结构: C++ 程序是一种多文件的程序,即一个工程文件。其中可以只包含一个 .cpp 文件,也可以包含多个 .cpp 文件,还可以包含其他类型的文件,如头文件( .h 文件)等。对于含有多个文件的 C++ 程序,经过编译生成各自的目标文件,再经过连接,生成一个可执行文件,这给程序的管理和维护带来了诸多的便利。•变量的划分:根据 C++ 程序的多文件结构和作用域,可以将变量分为两大类:局部变量和全局变量。⑴局部变量:是指定义在函数体内或块内的变量。局部变量又包含自动类局部变量和静态局部变量。自动类变量是在函数体内或分程序内定义的饿变量,它们的作用域粉笔在所定义的函数体内或分程序中。定义时可加 auto 说明,也可不加。静态局部变量是定义在函数体内或分程序中,并且用说明符 static 说明的一种变量。它的作用域与自动变量相同。但其生命期长,这是可见性与存在性不一致的一种变量。
  38. 38. ⑵全局变量:是指程序级在程序级或文件级的变量。包含外部变量和外部静态变量。外部变量的作用域是程序级的,即在一个文件中定义的外部变量,在该程序的 其他文件中也是可见的,只不过在其他文件中引用这个外部变量时要加以说明。说明外部变量时应在变量名前加 extern 表示该变量是个部变量。换句话说,在一个文件中定义的外部变量在另一个文件中要引用,则在引用前必须提前说明。在一个程序中,一个外部变量只能定义一次,但可以说明多次。在全局变量前加一个 static ,使该变量就在这个源文件中可用,称之为全局静态变量,也叫静态全局变量。局部变量和全局变量的可见性和生命期如下表所示:变量类型作用域自动型局部变量静态局部变量外部变量静态全局变量可见性在函数替内或块内可见
  39. 39. 在函数体或块内可见在整个程序中可见在定义它的文件中可见生命期函数或块执行完毕,其生命期结束程序执行完毕,其生命期结束程序执行完毕,其生命期结束程序执行完毕,期生命期结束例 10 :分析下列程序的执行结果。#include <iostream.h>voidfunc();
  40. 40. void main(){int x=21;staticint y;cout<<”x=”<<x<<”,”<<”y=”<<y<<endl;func();func();}voidfunc(){int x=5;static y=34;x-=2;
  41. 41. y+=20;cout<<”x=”<<x<<”,”<<”y=”<<y<<endl;}输出结果如下:x=21,y=0x=3,y=54x=3,y=74例 11 :分析下列程序的输出结果:该程序由四个文件组成: main.cpp 、 file1.cpp 、 file2.cpp 和 file3.cpp******************main.cpp***********************#include<iostream.h>
  42. 42. void func1();void func2();void func3();inti=5;void main(){i=20;func1();cout<<”main():i=”<<i<<endl;func2();cout<<”main():i=”<<i<<endl;func3();cout<<”main():i=”<<i<<endl
  43. 43. }**************************file1.cpp*************************#include<iostream.h>staticinti;void func1(){i=50;cout<<”func1():i(static)=”<<i<<endl;}**************************file2.cpp***************************#include<iostream.h>void func2()
  44. 44. {inti=15;cout<<”func2():i(auto)=”<<i<<endl;if(i){externinti;cout<<”func2():i(extern)=”<<i<<endl;}}***************************file3.cpp*****************************externinti;void func3(){
  45. 45. i=30;Cout<<”func3():i(extern)=”<<i<<endl;If(i){inti=10;cout<<”func3():i(auto)<<i<<endl;}}该程序的运行结果为:func1():i(static)=50main():i=20func2():i(auto)=15
  46. 46. func2():i(extern)=20main():i=20func3():i(extern)=30func3():i(auto)=10main():i=30static首先,static 是什么意思?是声明一个静态变量这个变量,可以是全局的,也可以是局部的偶这么理解,有问题不?函数可以看作是模块,程序文件也可以看作是模块。模块便是只认输入/输出,完成一定功能的黑盒。在过程化程序设计中,为了使程序文件发挥模块的作用,有必要定义一种模块的局部量,它区别于其他程序文件,函数内部定义的变量,对于程序而言,是局部的(局部变量);但是对于函数而言,是全局的(全局变量),

×