《C程序的结构》PPT课件.ppt_第1页
《C程序的结构》PPT课件.ppt_第2页
《C程序的结构》PPT课件.ppt_第3页
《C程序的结构》PPT课件.ppt_第4页
《C程序的结构》PPT课件.ppt_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

本章主要内容,作用域与可见性 对象的生存期 数据与函数 静态成员 共享数据的保护 友元 编译预处理命令 多文件结构和工程,5.1 面向对象程序的结构,5.1.1 作用域和生存期 1. 作用域 1) 函数原型作用域 函数原型作用域开始于函数原型声明的左括号“(”,结束于右括号“)”。例如: double Area(double length, double width); 函数原型作用域是C+程序中最小的作用域。 由于形参length和width只在括号之内有效,在程序的其它地方无法引用这个标识符,如果要引用,必须重新定义。因此,这里的标识符length和width实际上是可有可无的,省去它,也决不会影响到程序的编译和运行结果。例如: double Area(double, double);,块作用域又称局部作用域。由一对花括号“ ”所括起来的块中声明的标识符的作用域从声明处开始,一直到块结束的花括号为止。例如: #include void main( ) void fun1( ) ; int n; for( int i=0 ; i5; i+ ) int m ; if( i%2 ) n+ ; m = n/2 ; /错误,m未定义 n = i ; fun1( ) ; /fun1( )函数调用 ,2) 块作用域,void fun1( ) cout“i=“iendl ; /错误,i未定义 编译时,函数fun1( )中的语句: cout“i=“iendl; 将出现一个未定义错误,这是因为块作用域不能延伸到子函数 中。,3) 文件作用域,#include int k; void main() k=5; k+; int k=7; k+; cout“k=“k; cout“, k=“kendl; 程序运行结果为:k=8, k=6 可见性遵循的一般规则: (1) 标识符在引用前必须先声明。 (2) 在互相没有包含关系的不同作用域中声明同名的标识符时, 两标识符互不影响。 (3) 如果在两个或多个具有包含关系的作用域中声明了同名标识 符,则外层标识符在内层不可见。,1) 静态生存期 静态生存期与程序的运行期相同。具有文件作用域的变量具有静态生存期。如果要在函数内部的块作用域中声明具有静态生存期的变量,则要使用关键字static。 例如: static int k; 具有静态生存期的变量,也称为静态变量。 2) 局部生存期 在块作用域中声明的变量具有局部生存期。此生存期诞生于声明点,而终止于其作用域的结束处。具有局部生存期的变量都具有块作用域。但当在块作用域内将变量说明为静态变量时,该变量则具有静态生存期。 3) 动态生存期 动态生存期由程序中特定的函数 ( malloc( )和free( ) ) 调用或由操作符 ( new和delete ) 创建和释放。具有动态生存期的变量在内存的堆区分配空间。,2生存期,3局部变量和全局变量,1) 局部变量 局部变量包括自动(auto)变量、内部静态(static)变量和函数参数。 2) 全局变量 全局变量具有文件作用域。,/EX5_1.cpp : 演示局部变量和全局变量 #include int i = 1 ; /全局变量i: 静态生存期 void main( ) static int a ; /声明局部静态变量a: 静态生存期 int b = -10 ; /声明局部变量b: 局部生存期 int c = 0 ; /声明局部变量c: 局部生存期 void other( void ) ; /声明函数other( ) cout“ main: “i=“i“ a=“a“ b=“b“ c=“ cendl ; c = c + 8 ; other( ) ; /调用函数other( ) cout“ main: “i=“i“ a=“a“ b=“b “ c=“cendl; other( ); /调用函数other( ) ,void other( void ) static int a = 1 ; /局部静态变量a: 静态生存期 static int b ; /局部静态变量b: 静态生存期 int c = 5 ; /局部变量c: 局部生存期 i = i+2 ; a = a+3 ; c = c+5 ; cout“other: “i=“i“ a=“a“ b= “b “ c=“cendl; b = a ; 程序运行结果为: main: i=1 a=0 b=-10 c=0 other: i=3 a=4 b= 0 c=10 main: i=3 a=0 b=-10 c=8 other: i=5 a=7 b= 4 c=10,静态成员为同类的所有对象共同拥有,用于解决同类对象之间数据和函数的共享问题。静态成员分为静态数据成员和静态函数成员。 (1) 静态数据成员声明:static int n (2) 静态数据成员必须要在类外进行初始化,初始化的形式为: := 例如:int Point:n = 0 ; (3) 静态成员属于类,而不属于任何一个对象; (4) 静态成员一样要服从访问控制限制; (5) 私有静态数据成员只能在类内引用,公有或保护静态数据 成员可以在类外通过类名引用。 (6) 静态函数成员可以直接引用该类的静态成员,但不能直接 引用非静态数据成员; (7) 公有静态函数成员可以通过类名或对象名来调用。,5.1.2 静态成员,/EX5_2.cpp : 演示使用静态成员 #include class point private: int x , y ; static int countP ; /声明私有静态数据成员 public: point( int xx=0, int yy=0 ) /定义构造函数 x=xx ; y=yy ; countP+ ; point( point /员在类内引用,point:point( point /第3次通过类名调用静态函数成员 ,在主函数中,分别采用类名和对象名来调用get_c( )。 第1次调用get_c( )时由于还没有任何对象生成,只能采用 类名的形式。由此可见,通过类名调用静态函数成员可以输出 静态数据成员的初始值。 后面的2次get_c( )的调用既可以采用类名的形式,也可以 采用对象名的形式。 程序运行结果为: Object id = 0 point a, 4, 5 Object id=1 point b, 4, 5 Object id=2,/ 演示使用静态成员 #include “iostream.h“ #include “string.h“ class stu private: char *name,*num; static int total; public: stu(char *,char *); stu(); void print(); static int gettotal()return total; ;,int stu:total=0; stu:stu(char *n1,char *n2) /*拷贝构造函数怎么设计?*/ name=new charstrlen(n1)+1; num=new charstrlen(n2)+1; strcpy(name,n1); strcpy(num,n2); +total; void stu:print() cout“n name:“name “n num: “num “n total: “totalendl; ,stu:stu() delete name; delete num; -total; int main(int argc, char* argv) stu a(“wang“,“000001“); stu b(“yang“,“000002“); stu c(“tang“,“000003“); a.print(); coutendl“total: “a.gettotal()endl; b.print(); coutendl“total: “stu:gettotal()endl; return 0; ,声明友元函数是为了使普通函数或其它类的成员函数能访问本类的成员,友元函数在类声明中由关键字friend修饰。 普通函数声明为友元函数的形式: friend (参数表) 其它类的成员函数声明为友元函数的形式: friend :(参数表) 说明: (1) 友元函数的声明可以在类声明中的任何位置,既可在public区,也可在protected区,意义完全一样。 (2) 友元函数的定义一般放在类的外部,最好与类的其他成员函数定义放在一起。,5.1.3 友元 1. 友元函数,/EX5_3.cpp : 演示使用普通函数作友元函数计算两点距离 #include #include class point private: double x, y ; public: point(double xx=0, double yy=0 ) x=xx; y=yy; double get_x( ) return x; double get_y( ) return y; friend double distance( point p1, point p2 ) ; /普通函数作 ; /point的友元,double distance( point p1, point p2 ) /定义point类的友元函数 return (sqrt(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y); void main( ) point myp1(1,1), myp2(4,5) ; /声明point类对象myp1和myp2 cout“The distance is:“distance(myp1, myp2)endl; ,友元函数必须先接收对应类的对象,然后通过接收到的对象访问其所以成员,如果友元是一个类,则称为友元类。友元类的声明形式为: friend class 说明: (1) 友元类的声明同样可以在类声明中的任何位置; (2) 友元类的所有成员函数都成为友元函数。 例如,若A类为B类的友元类,即在B类中声明: friend class A ; 则A类的所有成员函数都成为B类的友元函数,都可以访问B类 的私有和保护成员。,2. 友元类,友元类的成员函数可以通过对象名直接访问到隐藏的数据, 达到高效协调工作的目的。但在使用友元时还有两点需要注意: (1) 友元关系不能传递。B类是A类的友元,C类是B类的友 元,C类和A类之间如果没有声明,就没有任何友元关系,不能进行数据共享。 (2) 友元关系是单向的。如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有和保护数据。,例:友元成员函数,#include “string.h“ #include “iostream.h“ class st_n; class sco private: int mat,eng; public: sco(int i1,int i2):mat(i1),eng(i2) void show( ) cout“n math:“mat; cout“n eng: “eng; void show(st_n ,class st_n private:char *name,*num; public: friend void sco:show(st_n ,void sco:show(st_n ,使用const关键字声明的引用称为常引用,常引用所引用的对象不能被更新。用常引用做形参,不会发生对实参意外的更改。 常引用的声明形式为 const & 注意:常引用的值不能被更新,所以常引用声明时, 必须同时进行初始化。,5.1.4 常类型 1. 常引用,/EX5_4.cpp : 演示常引用做形参 #include void display( const double 则得程序运行结果为: r=6.5,使用const关键字声明的对象称为常对象。常对象的声明形式为 const 或 const 声明常对象的同时,也要进行初始化,而且该对象以后不能再被更新。 3. 常成员函数 使用const 关键字声明的函数称为常成员函数,常成员函数声明的形式为 (参数表) const;,2. 常对象,说明: (1) const是加在函数声明后面的类型修饰符,它是函数类型的一个组成部分,因此在实现部分也要带const关键字。 (2) const关键字可以被用于对重载函数的区分,例如,可以在类中这样声明: void fun( ) ; void fun( ) const ; (3) 常成员函数不能更新对象的数据成员,也不能调用该类中没有用const修饰的成员函数。 (4) 常对象只用于调用它的常成员函数,而不能调用其他成员函数。,/EX5_5.cpp : 演示常成员函数 #include class A private: int x , y ; public: A ( int i=0, int j=0 ) x=i ; y=j ; void fun( ) /定义普通成员函数 cout“成员函数:x=“x“, y=“yendl ; void fun( ) const /定义常成员函数 cout“常成员函数:x=“x“, y=“yendl ; ; void main( ) A obj1( 1, 2 ) ; /声明普通对象obj1 obj1.fun( ) ; /调用普通成员函数 const A obj2( 3, 4 ) ; /声明常对象obj2 obj2.fun( ) ; /调用常成员函数 ,程序运行结果为: 成员函数:x=1, y=2 常成员函数:x=3, y=4 4. 常数据成员 常数据成员也用关键字const说明,常数据成员(包括常引用、常对象)由于不能被更新,因此只能用成员初始化列表的方式通过构造函数进行初始化。,/EX5_6.cpp : 演示常数据成员 #include class A private: const int x ; /常数据成员x static const int y ; /静态常数据成员y public: const int /y的初始化在类外进行,void main( ) A obj1(1), obj2(2); obj1.fun( ); obj2.fun( ); 程序运行结果为: x=1, y=5, r=1 x=2, y=5, r=2,大型程序通常由多个文件组成一个项目(Project),理由 是: 1. 将相关类和函数放在一个特定的文件中,对不同的文件进行 单独编写、编译,最后再链接,避免重复劳动,提高工作效益。 2. 便于团队开发。按逻辑功能将程序分解成多个源文件,使程 序容易管理,便于程序员的任务安排。 大型程序基本上由三个部分构成: 类的声明: 通常做成 .h文件 (Header Files) 类成员的实现:通常做成 . cpp文件(Source Files) 主函数: 通常做成 . cpp文件(Source Files),5.1.5 多文件结构,5.2 动态内存分配,5.2.1 new运算符 new运算符用于动态分配一块内存空间。使用形式为: 指针变量 = new 长度 例如分配一个可以容纳256个char型数据的空间: char *Cbuffer = new char 256 ; 使用new运算符时,需要注意: (1) 如果分配的空间长度为1个单位,则可以省略 和其中的整数,例如: float *pNum=new float ;与 float *pNum=new float1;等价。,(2) 使用new运算符分配内存空间时,其空间长度可以是变量, 也可以是数值表达式,例如分配一个可以容纳10个int型数 据的空间: int nSize = 5 ; int *nPInt = new intnSize+5; (3) 由new分配的内存空间是连续的,可以通过指针的变化访问 所分配空间的每一个元素,例如: int *nPInt = new int10; nPInt5=100; 或 *(nPInt+5)=100; (4) 如果当前存储器无足够的内存空间可分配,则new运算符返 回0 ( NULL )。,由new运算符分配的内存空间在使用完毕后应该使用delete运算符释放。delete运算符的使用有两种形式: delete指针 或 delete 指针 例如:int *pInt = new int ; delete pInt ; int *pManyInt=new int10 ; delete pManyInt ; 使用delete运算符时,需要注意: (1)用new运算符获得的内存空间,只许使用一次delete,不允许多次对同一块空间进行多次释放,否则将会产生严重错误。 (2) delete只能用来释放由new运算符分配的动态内存空间,不得使用delete运算符去释放程序中的变量、数组的存储空间。,5.2.2 delete运算符,1链表概述 链表是一种动态数据结构,它的特点是用一组任意的存储单元 ( 可以是连续的,也可以是不连续的 ) 存放数据元素。一个简单的链表具有下图所示的结构形式。,5.2.3 动态内存分配的应用实例,定义单链表结构的最简单形式为: struct Node int data; Node *next; ;,定义一个链表类List,其中包含链表结点的插入、删除、 访问等功能的成员函数,以便对链表进行操作。 class List Node *head; /声明一个链表结构指针 public: List( ) head = NULL ; void InsertList ( int aData , int bData ) ;/链表结点的插入 void DeleteList ( int aData ) ; /链表结点的删除 void OutputList ( ) ; /链表结点的访问 Node *Gethead( ) return head ; ;,void List:OutputList( ) /链表结点的访问 Node *current = head ; /建立链表头指针 while ( current != NULL ) /如果链表存在, coutdatanext ; /指向下一个结点 coutendl ; 3链表结点的插入 如果要将新结点b插入到链表的结点a之前,则需要考虑下列几种情况:,2链表结点的访问,(1) 插入前链表是一个空表,插入新结点b后,链表如图 (a)所示。 (2) 若a是链表的第一个结点,插入新结点b后成为第一个结点,如图 (b)所示。 (3)若a不是链表的第一个结点,则要先找出a的上一个结点ak,然后新结点b插到结点ak 与a之间,如图 (c)所示。 (4) 若链表中不存在a,则新结点b插在最后,如图 (d)所示。,/设aData是结点a中的数据,bData是新结点b中的数据 void List:InsertList( int aData , int bData ) Node *p , *q , *s ; s = ( Node* ) new Node ; /动态分配一个新结点存储区 s-data = bData ; /将新结点b的数据放入新存储区 p = head ; /结点指针p指向链表头 if ( head = NULL ) /若是空表, head = s ; /将新存储区的地址赋给表头,即使 s-next = NULL ; /新结点b作为第一个结点 else /若不是空表 if( p-data = aData ) /若a是第一个结点 head = s; /使新结点b作为第一个结点 s-next = p; /将结点a接到新结点b的后面 ,else /若a不是第一个结点 while( p-data != aData /将新存储区排在链表末尾。 ,要在链表中删除结点a,并释放被删除的结点所占的存储空间,需要考虑下列几种情况: (1) 若要删除的结点a是第一个结点,则把head指向a的下一个结点,如图 (a)所示。 (2) 若要删除的结点a不是第一个结点,则应使a的上一结点ak-1的指针域指向a的下一个结点ak+1,如图 (b)所示。 (3) 若空表或要删除的结点a不存在,则不作任何改变。,4链表结点的删除,/设aData是要被删除结点a中的数据成员 void List:DeleteList ( int aData ) Node *p , *q ; p = head ; if ( p = NULL ) return ; /若p为空,则返回 if ( p-data = aData ) /若a是第一个结点 head = p-next; /链表头指向下一个结点 delete p ; /删除结

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论