C语言编程[共268页]_第1页
C语言编程[共268页]_第2页
C语言编程[共268页]_第3页
C语言编程[共268页]_第4页
C语言编程[共268页]_第5页
已阅读5页,还剩263页未读 继续免费阅读

下载本文档

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

文档简介

1、C+语言编程,宁 博,程序设计方法的发展历程,面向过程的程序设计方法 程序的目的:用于数学计算 主要工作:设计求解问题的过程 缺点:对于庞大、复杂的程序难以开发和维护,程序设计方法的发展历程,面向过程的结构化程序设计方法 设计思路 自顶向下、逐步求精。采用模块分解与功能抽象,自顶向下、分而治之 程序结构 按功能划分为若干个基本模块 各模块间的关系尽可能简单,功能上相对独立;每一模块内部均是由顺序、选择和循环三种基本结构组成 其模块化实现的具体方法是使用子程序,程序设计方法的发展历程,面向过程的结构化程序设计方法 优点 有效地将一个较复杂的程序系统设计任务分解成许多易于控制和处理的子任务,便于开

2、发和维护,程序设计方法的发展历程,面向过程的结构化程序设计方法 缺点:可重用性差、数据安全性差、难以开发图形界面的应用 把数据和处理数据的过程相互独立 当数据结构改变时,所有相关的处理过程都要进行相应的修改 图形用户界面的应用,很难用过程来描述和实现,开发和维护都很困难,面向对象的设计思想,面向对象的程序设计方法 将数据及对数据的操作方法封装在一起,作为一个相互依存、不可分离的整体对象。 对同类型对象抽象出其共性,形成类。 类通过一个简单的外部接口,与外界发生关系 基本设计思想 封装 软件复用,面向对象的设计思想,面向对象的程序设计方法 优点 程序模块间的关系更为简单,程序模块的独立性、数据的

3、安全性就有了良好的保障。 通过继承与多态性,可以大大提高程序的可重用性,使得软件的开发和维护都更为方便,面向对象的基本概念 - 对象,一般意义上的对象 是现实世界中一个实际存在的事物。 可以是有形的(比如一辆汽车),也可以是无形的(比如一项计划)。 是构成世界的一个独立单位,具有: 静态特征:可以用某种数据来描述 动态特征:对象所表现的行为或具有的功能,面向对象的基本概念 - 对象,面向对象方法中的对象 是系统用来描述客观事物的一个实体,它是用来构成系统的一个基本单位。对象由一组属性和一组行为构成。 属性:用来描述对象静态特征的数据项。 行为:用来描述对象动态特征的操作,面向对象的基本概念 -

4、 类,分类人类通常的思维方法 分类所依据的原则抽象 忽略事物的非本质特征,只注意那些与当前目标有关的本质特征,从而找出事物的共性,把具有共同性质的事物划分为一类,得出一个抽象的概念。 例如,石头、树木、汽车、房屋等都是人们在长期的生产和生活实践中抽象出的概念,面向对象的基本概念 - 类,面向对象方法中的类 具有相同属性和行为的一组对象的集合 为属于该类的全部对象提供了抽象的描述,包括属性和行为两个主要部分。 类与对象的关系:犹如模具与铸件之间的关系,一个属于某类的对象称为该类的一个实例,面向对象的基本概念 - 封装,把对象的属性和行为结合成一个独立的系统单位 尽可能隐蔽对象的内部细节。对外形成

5、一个边界(或者说一道屏障),只保留有限的对外接口使之与外部发生联系,面向对象的基本概念 - 继承,继承对于软件复用有着重要意义,是面向对象技术能够提高软件开发效率的重要原因之一。 定义:特殊类的对象拥有其一般类的全部属性与行为,称作特殊类对一般类的继承。 例如:将Person作为一个一般类,Student便是一个特殊类,面向对象的基本概念 - 多态性,多态性是指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或行为在一般类及其各个特殊类中具有不同的语义。 例如: 数的加法-实数的加法 -复数的加法,C+语言概述,C+语言的产生 C+的特点

6、 一个简单的C+程序实例,C+语言的产生,C+是从C语言发展演变而来的,首先是一个更好的C。 引入了类的机制,最初的C+被称为带类的C。 1983年正式取名为C+。C+语言的标准化工作从1989年开始,于1994年制定了ANSI C+标准草案。以后又经过不断完善,成为目前的C,C+的特点,全面兼容C 它保持了C的简洁、高效和接近汇编语言等特点 对C的类型系统进行了扩充 C+也支持面向过程的程序设计,不是一个纯正的面向对象的语言 支持面向对象的方法 类、对象、继承、抽象、封装,一个简单的C+程序实例,include void main(void) coutHello!n; coutWelcome

7、 to c+!n;,一个简单的C+程序实例,运行结果: Hello! Welcome to c+,注释,C中的注释:块注释 /* */ /* This is a comment */ 不允许嵌套 C+中的注释 C+继承了C的块注释方式 增加了一种行注释方式 C+把任何一行中从“/”开始直到该行结束的所有内容皆视为注释,注释 - 一个简单的例子,include #include void main() / Checking if a keyword is ESC int i, key; while( 1 ) key = getch(); / Get a key from console if (

8、key = x1B printf(“nEscape! ”); return; else printf(“nKeycode is %2XH”, key);,作用域,模块:在C语言中模块的概念是指在花括号之间的一组语句 作用域的种类 局部模块作用语:变量定义在模块范围内 文件作用域:变量定义在全局范围内,只限于当前文件的存取; 全局作用域:变量定义在全局范围内,对全程序有效。实现方式:include和extern 类作用域:变量定义在类中,在类范围内有效,作用域,: 运算符: 指明作用域。 例 int x; void f() int x=1; :x=2; return;,作用域 - 一个简单的例子

9、,include int global = 10; void main() int global = 5; printf(“The value of global is : %dn”, global); return;,作用域 - 作用域分辨操作符,全局变量访问 :global #include int global = 10; void main() int global = 5; printf(“The value of inner global is : %dn”, global); printf(“The value of outer global is : %dn”, :global

10、); return;,指针,指针是C语言的一个非常重要的特征 实际上是内存地址,非常灵活且非常高效 但又潜伏着非常大的危险性 具有数据类型,可以进行指针运算 无值型指针,void *,是一种非常有用且十分灵活的指针类型,常量指针,定义格式 const type * ptr_name; 其含义是指向常量的指针 不允许通过指针来修改其指向的对象的值 可以修改指针的值 例子 const int * ptr; const int i=10; ptr = / 错误操作,试图修改指针指向的内容,常量指针,例子 const char * ptr; const char str10=“hehehe”; ptr

11、 = str; / 指针赋值 ptr3 = ; / 错误操作,试图修改指针指向的内容,常量指针,const int * ptr; int i=10; ptr = 输出结果为:11,常量指针,不允许将const类型的变量地址赋值给一般的变量指针 int * ptr; const int i = 10; ptr = 输出结果为:11,指针常量,定义格式 type * const ptr_name; 其含义是指针变量的值不可改变 不允许修改指针变量的地址值 可以修改指针指向的变量值,如果指向的对象不是一个常量的话 例子 int * const ptr1; void * const ptr2,指针常量

12、,int num=10; int * const const_ptr = / 编译错误 /试图修改常量指针指向的对象值,void类型,1.说明函数没有返回值; void fun(void) return ; 2.表示函数不需要任何入口参数; double fun(void) 3.可将指针说明为void型。这种指针可被赋以其它任何类型的指针。 double a=9.0; double *pd,练习,用指针写一个swap函数,交换两个整数 a和b的值。打印交换前后a,b的值,引用,先看一个简单的例子 int i, / output: j=3,引用,引用的定义格式 type 引用定义说明 引用必须在

13、定义时进行初始化 被引用的变量必须在引用定义之前定义 引用一经定义,便无法重新引用其它变量,引用,对引用概念的理解 int i=10, 在物理存储中,变量i有存储单元,但引用j没有存储单元,其具体表现是变量i和引用j的物理地址是相同的 内存单元 0XEFFF21 有两个名字,可以将引用j理解为变量i的别名 在同一个模块中的引用没有太大意义,但在函数调用时可以实现传名调用,10,变量i,引用j,0XEFFF21,练习,用引用写一个swap函数,交换两个整数 a和b的值。打印交换前后a,b的值,C+的内存格局,全局数据区(data area) 代码区(code area) 栈区(stack are

14、a) 堆区(heap area,C+的内存格局,全局变量、静态数据、常量存放在全局数据区; 所有类成员函数和非成员函数代码存放在代码区; 为运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区;其余的空间都被称为堆区,堆内存的分配与释放,当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。 在C+中,申请和释放堆中分配的存贮空间,分别使用new和delete的两个运算符来完成,其使用

15、的格式如下: 指针变量名=new 类型名(初始化式); delete 指针名; new运算符返回的是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有名字,堆内存的分配与释放,C中的malloc和free函数在C+中可以用 alloc.h头文件中声明 void * malloc(size_t size); void free(void *,堆内存的分配与释放,if (array=(int*)malloc(arraysize*sizeof(int)=NULL) cout“cant allocate more memory.n”; ex

16、it(1); free(array,堆内存的分配与释放,new new 类型名T(初值列表) 功能:在程序执行期间,申请用于存放T类型对象的内存空间,并依据初值列表调用合适的构造函数。 结果值:成功:T类型的指针,指向新分配的内存。失败:0(NULL,堆内存的分配与释放,delete delete 指针P 功能:释放指针P所指向的内存。P必须是new操作的返回值,堆内存的分配与释放,用初始化式(initializer)来显式初始化 例如: int *pi=new int(0); 当pi生命周期结束时,必须释放pi所指向的目标: delete pi; 注意这时释放了pi所指的目标的内存空间,也就

17、是撤销了该目标,称动态内存释放(dynamic memory deallocation),但指针pi本身并没有撤销,它自己仍然存在,该指针所占内存空间并未释放,堆,i,用初始化式(initializer)来显式初始化 例如: int *pi=new int(0); 当pi生命周期结束时,必须释放pi所指向的目标: delete pi; 注意这时释放了pi所指的目标的内存空间,也就是撤销了该目标,称动态内存释放(dynamic memory deallocation),但指针pi本身并没有撤销,它自己仍然存在,该指针所占内存空间并未释放,堆内存的分配与释放,堆,i,堆内存的分配与释放,对于数组进

18、行动态分配的格式为: 指针变量名=new 类型名下标表达式; delete 指向该数组的指针变量名,堆内存的分配与释放,if (array=new int arraysize)=NULL) cout“cant allocate more memory.n”; exit(1); delete array,堆内存的分配与释放,例】动态数组的建立与撤销 #include #include void main() int n; char *pc; coutn; pc=new charn; / strcpy(pc,堆内存的动态分配); coutpcendl; delete pc; / 撤销并释放pc所指

19、向的n个字符的内存空间 return,堆内存的分配与释放,动态分配的三个特点:首先,变量n在编译时没有确定的值,而是在运行中输入,按运行时所需分配堆空间,这一点是动态分配的优点,可克服数组“大开小用”的弊端。delete pc是将n个字符的空间释放,而用delete pc则只释放了一个字符的空间; 其次如果有一个char *pc1,令pc1=p,同样可用delete pc1来释放该空间。尽管C+不对数组作边界检查,但在堆空间分配时,对数组分配空间大小是纪录在案的。 第三,没有初始化式(initializer),不可对数组初始化,堆内存的分配与释放,指针使用的几个问题: 动态分配失败。返回一个空

20、指针(NULL),表示发生了异常,堆资源不足,分配失败。 指针删除与堆空间释放。删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除本身,释放堆空间后,成了空悬指针,堆内存的分配与释放,内存泄漏(memory leak)和重复释放。new与delete 是配对使用的, delete只能释放堆空间。如果new返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。 动态分配的变量或对象的生命期。无名对象,它的生命期并不

21、依赖于建立它的作用域,比如在函数中建立的动态对象在函数返回后仍可使用。我们也称堆空间为自由空间(free store)就是这个原因,练习,建立动态整型数组 用户输入数组长度, 并且用户输入初始化数组, 求和并打印到屏幕,练习,编写程序。测试堆内存的容量:每次申请一个数组,内含100个整数,直到分配失败,并打印堆容量,面向对象编成的基本特点,抽象 封装 继承 多态性,面向对象编成的基本特点 -抽象,抽象是对具体对象(问题)进行概括,抽出这一类对象的公共性质并加以描述的过程。 只注意问题的本质及描述,而忽略实现过程或细节。 数据抽象:描述某类对象的属性或状态(对象相互区别的物理量)。 代码抽象:描

22、述某类对象的共有的行为特征或具有的功能。 抽象的实现:通过类定义中的public来实现。 抽象出来的数据和行为对外是可见的,面向对象编成的基本特 - 抽象,class Watch public: void SetTime(int NewH, int NewM, int NewS); void ShowTime(); private: int Hour,Minute,Second;,抽象的行为,面向对象编成的基本特点 -封装,将实现细节涉及到的数据成员、实现代码封装在类中,对外是不可见的。 目的是曾强安全性和简化编程,使用者不必了解具体的实现细节,而只需要通过外部接口,以特定的访问权限,来使用类

23、的成员 实现封装:通过类定义中的private来实现,面向对象编成的基本特点 -封装,class Watch public: void SetTime(int NewH, int NewM, int NewS); void ShowTime(); private: int Hour,Minute,Second;,封装的数据成员,面向对象编成的基本特点 -继承,继承是C+中支持层次分类的一种机制,允许程序员在保持原有类特性的基础上,进行更具体的类定义,形成一个类层次关系 继承的主要目的和作用 代码复用 提高程序设计语言的建模能力 接近现实世界的实际模型,也就是模型表达能加自然,这样使得建模现实世

24、界更加容易 具体的内容将在后面的章节中介绍,面向对象编成的基本特点 -多态性,多态的概念:同一名称,不同的功能实现方式。 目的:达到行为标识统一,减少程序中标识符的个数,类的概念和定义,类的概念 类是用来描述一组对象的相同属性和行为,它为属于该类的全部对象提供了统一的抽象描述 包括抽象属性和抽象行为 利用类可以实现细节进行封装 包括用于实现的成员数据和成员函数 利用类易于编写大型复杂程序,其模块化程度比C中采用函数更高,类的概念和定义,类的定义 class 类名称 public: 公有成员(外部接口) private: 私有成员 (实现细节) protected: 保护型成员 (用于类层次的访

25、问控制) 类是一种用户自定义的类型,类的概念和定义,class Watch public: void SetTime(int NewH, int NewM, int NewS); void ShowTime(); private: int Hour, Minute, Second;,成员数据,成员函数,类的概念和定义,void Watch : SetTime(int NewH, int NewM, int NewS) Hour=NewH; Minute=NewM; Second=NewS; void Watch : ShowTime() coutHour:Minute:Second;,类的概念

26、和定义,成员数据 与一般的变量定义相同,但需要将它放在类的定义体中 成员函数 在类中说明原形,在类外定义函数体实现,并在函数名前使用类名加以限定。也可以直接在类中定义函数体,形成内联成员函数。 在类的定义外部实现内联成员函数时一定要显式加上inline关键词 允许定义重载函数和带缺省形参值的函数,类的概念和定义,内联成员函数 为了提高运行时的效率,对于较简单的函数可以声明为内联形式。 实现内联成员函数的方式: 将函数体放在类的定义中。 在外部实现中显式使用inline关键字,类的概念和定义,内联成员函数的内部实现 class Location public: void Init(int ini

27、tX, int initY) X=initX; Y=initY; int GetX() return X; int GetY() return Y; private: int X,Y;,内 联 成 员 函 数,类的概念和定义,内联成员函数的外部实现 class Location public: void Init(int initX, int initY); int GetX(); int GetY(); private: int X,Y;,类的概念和定义,内联成员函数的外部实现 inline void Location: Init(int initX,int initY) X=initX;

28、Y=initY; inline int Location:GetX() return X; inline int Location:GetY() return Y;,类的概念和定义,私有成员 (私有数据成员和私有成员函数) 在关键字private后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。 如果紧跟在类名称的后面声明私有成员,则关键字private可以省略,类的概念和定义,私有成员 class Watch private: int Hour,Minute,Second; public: void SetTime(int NewH, int NewM, int NewS);

29、void ShowTime();,private可以缺省,类的概念和定义,私有成员 class Watch w; int i; i=w.Hour; / 编译错误,试图访问私有成员数据 w.SetTime(); / 正确,因为SetTime是公有成员函数,类的概念和定义,公有成员(公有数据成员和公有成员函数) 在关键字public后面声明,它们是类与外部的接口,任何外部函数都可以访问公有类型数据和函数,类的概念和定义,公有成员 class Watch public: int Hour,Minute,Second; void SetTime(int NewH, int NewM, int NewS

30、); void ShowTime();,类的概念和定义,公有成员 class Watch w; int i; i=w.Hour; /正确,因为Hour是公有成员数据 w.SetTime(); / 正确,因为SetTime是公有成员函数,类的概念和定义,保护成员(保护数据成员和保护成员函数) 与private类似,在类的外部函数中不能访问类中的保护成员 在类的子类中可能可以访问该类的保护成员,这取决于访问控制,在后面讲述,类的概念和定义,不能试图给类定义中的数据成员进行初始化 类仅仅是类型的说明,而对象的数据成员的初始化必须有构造函数来完成,class Watch private: int Ho

31、ur = 0, Minute = 0, Second = 0; public: void SetTime(int NewH, int NewM, int NewS); void ShowTime();,错误,C+中的结构,C+中的结构比C语言中的结构具有更加强大的功能 在C+中结构和类具有类似的功能 在结构中可以定义成员函数、可以进行继承;可以象C+的类一样实现; 所有的解释与类相同,除了 只是缺省的访问控制是public,而类的缺省访问控制是private 结构是C+扩展C的第一步,但不推荐这种结构编程方式,C+中的结构,Struct Person int age; int getAge()

32、 return age; ; ; Struct Student : Person int sno; int getSno() return sno; ;,对象,类的对象是该类的某一特定实体,即类类型的变量。 定义形式: 类名 对象名; 例: watch myWatch; 当然也可以有对象的指针,对象的引用等,对象,类中成员的访问方式 类中的成员函数访问类中的成员数据 直接使用成员名 类外访问 使用“对象名.成员名”方式访问 public 属性的成员,对象,类中成员的访问方式 #include class Watch ./类的定义略 /.类的实现略 void main(void) Watch m

33、yWatch; myWatch.SetTime(8,30,30); myWatch.ShowTime();,构造函数,构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态。 在对象创建时由系统自动调用。 如果程序中未定义出,则系统自动产生出一个缺省形式的构造函数 - 缺省构造函数 允许为内联构造函数、重载构造函数、带缺省形参值的构造函数,构造函数,定义说明 构造函数名与所在的类名相同; 构造函数没有返回类型,因此在定义构造函数时不能带有任何带有返回值的返回语句; 不能将构造函数说明为void类型; 可以有返回语句 return; 构造函数只能用于构造类的实例对

34、象,它的调用是隐含的,不能对任何已经构造的对象再次进行构造函数的显式调用,构造函数,定义说明 构造函数一般总是被定义为公有成员,否则在外部定义类对象时无法对其进行初始化 构造函数的定义与普通成员函数一样,可以在类定义体内部,也可以放在类定义体的外部,且可以直接访问其类所在的所有其他成员,包括成员数据和成员函数,构造函数,定义说明 class Person int age; Person() age=0; ; ; class Student :public Person int stno; ; Person p; / 编译错误,必须将该构造函数变为公有成员,构造函数,一个类可以有多个构造函数,和

35、普通函数一样,同名的构造函数相互重载 Class d_String Public: d_String(); d_String(const d_String *); d_String(const char *);,构造函数,对象的初始化 d_String str1; / 调用缺省构造函数 d_String str1(); / 调用缺省构造函数 d_String str1(“Bing Wang”); / 调用构造函数 d_String str1=d_String(); / 调用缺省构造函数 d_String str1=d_String(“Bing Wang”); / 调用构造函数,构造函数,构造函

36、数一般用来对对象的成员数据进行初始化 当类的成员数据比较多时这种初始化语句比较多 Class Account public: Account() _name = 0; _balance = 0.0; _acct_nmbr = 0;,构造函数,Account(const char * name, double balance, int acct_nmbr) _name = new char strlen(name)+1 ; strcpy(_name, name); _balance = balance; _acct_nmbr = acct_nmbr; ; .,构造函数,成员初始化表 Class

37、Account public: Account() : _name ( 0), _balance (0.0), _acct_nmbr (0) ; Account(const char * name, double balance, int acct_nmbr) : balance = balance, _acct_nmbr = acct_nmbr; _name = new char strlen(name)+1 ; strcpy(_name, name); ; . ; 初始化列表的效率比赋值语句的效率要高,成员初始化表,构造函数,const成员函数 一个类中的成员函数可以是const clas

38、s d_Set public: d_Set(); unsigned long cardinality() const; d_Boolean is_empty() const;,const成员函数,const成员函数含义是该函数只能读取该类中的成员数据,而不能修改,因此 该成员函数不能修改所在类的成员数据 该成员函数不能调用所在类中的非const成员函数 根据const成员函数的定义 不能将构造函数定义为const类型,因为它要初始化成员数据的值 const关键字可以被用于参与对重载函数的区分 const是函数类型的一个组成部分,因此在实现部分也要带const关键字,const对象,const对

39、象与其他类型的const对象一样 const对象调用构造函数初始化对象后不能再被修改 const d_String str1 = “Bing Wang”; . str1 = “Bing Wang”; /错误 通常,const对象只能调用const成员函数,举例,include class R public: R(int r1, int r2)R1=r1;R2=r2; void print(); void print() const; private: int R1,R2;,举例,void R:print() coutR1:R2endl; void R:print() const coutR1;

40、R2endl; void main() R a(5,4); a.print(); /调用void print() const R b(20,52); b.print(); /调用void print() const,隐含的this指针,来看一个例子 Class ArrayX Private : int dim; double * x; Public : ArrayX(int d); ArrayX(); void WriteX( int n, double val); double ReadX(int n); void PrintX( int n ); void PrintAll( void )

41、;,隐含的this指针,问题:成员函数,例如ReadX,是如何知道当前对象的地址的呢?因为只有通过地址才能操作该对象中的数据成员;这正好是this指针的作用 为了解决上述问题,实际上在成员函数参数表中存在一个额外的参数: WriteX(Array * this, double val); ReadX(ArrayX * this, int n); PrintX(ArrayX * this, int n); PrintAll(ArrayX * this,隐含的this指针,这个ArrayX * this指针是隐含的,由他的调用这提供,指向被操作的对象 在成员函数内部也可以使用this指针,例如 V

42、oid Write(int n, double val) if (a dim) this-xn = val; 上述程序中this指针可缺省,Void Write(int n, double val) if (a dim) xn = val;,隐含的this指针,This指针除了上述用法之外,可以使用在返回值中 class Screen Public: Screen(); Screen,隐含的this指针,This指针除了上述用法之外,可以使用在返回值中 Screen,缺省构造函数,缺省构造函数是指没有参数的构造函数 当类的定义中没有定义构造函数时,系统会为该类生成一个缺省构造函数,在进行对象说

43、明时系统会调用系统生成的缺省构造函数 系统生成的缺省构造函数不做任何事情 当类中用户定义了构造函数后,编译器就会忽略系统生成的缺省构造函数,即使你没有定义缺省构造函数 建议用户定义自己的缺省构造函数,因为系统生成的缺省构造函数不做任何事情,缺省构造函数,Class d_String Public: d_String(); / 缺省构造函数 d_String(const d_String *); d_String(const char *); ; d_String str; / 调用用户定义的缺省构造函数,缺省构造函数,Class d_String Public: /d_String(); /

44、缺省构造函数 /d_String(const d_String *); /d_String(const char *); / 没有其它构造函数定义 ; d_String str; / 调用系统生成的缺省构造函数,缺省构造函数,Class d_String Public: /d_String(); / 缺省构造函数 d_String(const d_String *); d_String(const char *); ; d_String str; / 编译错误,因为编译器忽略系 / 统生成的缺省构造函数,拷贝构造函数,拷贝构造函数是一种特殊的构造函数,其形参为本类的对象引用 class 类名

45、public : 类名(形参);/构造函数 类名(类名 Y=yy; Location(Location,拷贝构造函数,如果没有定义类的拷贝构造函数,系统就会自动生成一个默认的拷贝构造函数,其功能是把初始值对象的每个数据成员的值都复制到新建立的对象中 何时调用拷贝构造函数 Location L1; Location L2(L1); / 调用拷贝构造函数 Location L3 = L1; / 调用拷贝构造函数 F( L1 ); / 调用拷贝构造函数 L1 = g(); /调用拷贝构造函数, 为被返回 / 的对象建立一个临时对象,拷贝构造函数,课堂提问 既然系统能够自动生成一个默认的拷贝构造函数,

46、那么用户是否还有必要生成自己的拷贝构造函数呢?理由是什么,浅拷贝与深拷贝,浅拷贝 - 通过一个例子来理解浅拷贝的概念,C语言的例子 char * p1, *p2; p1 = malloc( 20 ); strcpy(p1, “Bin Wang”); p2 = p1,Bin Wang,指针p1,指针p2,浅拷贝与深拷贝,浅拷贝 - 通过一个例子来理解浅拷贝的概念,C+的例子 Class String String(); String(const char *) String(); private: char * str;,String:String() str = 0; String:Strin

47、g() if (str!=0) delete str; String:String(const char * s) str = new char strlen(s)+1; strcpy(str, s); String * s1 = new String(“Bin Wang”); / String * s2 = new String (s1); / 调用缺省拷贝构造函数,浅拷贝与深拷贝,浅拷贝 - 通过一个例子来理解浅拷贝的概念 浅拷贝的缺点 当一个指针指向同一个对象或内存单元时存在潜在的错误源泉,例如 当对象s1被析构以后,对象s2无法析构是由于缺省拷贝构造函数引起的,必须重写,str,str

48、,Bin Wang,s1,s2,浅拷贝与深拷贝,深拷贝,Class String String(); String(const char *); String(String,String:String() str = 0; String:String() if (str!=0) delete str; String:String(const char * s) str = new char strlen(s)+1; strcpy(str, s); String:String(String,浅拷贝与深拷贝,深拷贝 深拷贝可以很好地避免指针悬挂问题,str,str,Bin Wang,s1,s2,B

49、in Wang,析构函数,完成对象被删除前的一些清理工作。 在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间。 如果程序中未定义析构函数,编译器将自动产生一个缺省的析构函数。 与构造函数一样,析构函数一般总是被说明为类的一个公有函数成员,由加上函数名称构成,没有返回值,且没有任何参数,析构函数,当一个对象中没有涉及动态内存分配时,可以使用系统生成的缺省析构函数。如果涉及到动态内存问题时,应该编写自己的显式析构函数;否则存在内存泄漏问题 当然也可能存在需要处理的情况:在对象的生命周期内动态获得的各种资源,在析构函数中应该需要处理;例如该对象获得的互斥锁,在析构函数中应该释放该锁

50、,析构函数,Class Account Public: Account(); Account ( const char *, double = 0.0 ); Account ( const Account,inline Account:account() delete _name;,例1,1) Account global( “James Joyce” ); (2) int main() (3) Account local ( Anna Livia Plurabelle”, 10000 ); (4) Account (10),例1,该例子中调用了4次构造函数; 对应地,程序也要调用4次析构函数

51、,类的应用举例,一圆型游泳池如图所示,现在需在其周围建一圆型过道,并在其四周围上栅栏。栅栏价格为35元/米,过道造价为20元/平方米。过道宽度为3米,游泳池半径由键盘输入。要求编程计算并输出过道和栅栏的造价,类的应用举例,include const float PI = 3.14159; const float FencePrice = 35.0; const float ConcretePrice = 20.0; /定义类Circle 及其数据和方法 class Circle private: float radius; public: Circle(float r); /构造函数 floa

52、t Circumference() const; /圆周长 float Area() const; /圆面积,类的应用举例,类的实现 / 构造函数初始化数据成员radius Circle:Circle(float r): radius(r) / 计算圆的周长 float Circle:Circumference() const return 2 * PI * radius; / 计算圆的面积 float Circle:Area() const return PI * radius * radius;,类的应用举例,void main () float radius; float FenceCo

53、st, ConcreteCost; / 提示用户输入半径 cout radius; / 定义 Circle 对象 Circle Pool(radius); Circle PoolRim(radius + 3,类的应用举例,计算栅栏造价并输出 FenceCost = PoolRim.Circumference() * FencePrice; cout Fencing Cost is $ FenceCost endl; / 计算过道造价并输出 ConcreteCost = (PoolRim.Area() - Pool.Area()*ConcretePrice; cout Concrete Cost

54、 is $ ConcreteCost endl;,类的应用举例,运行结果 Enter the radius of the pool: 40 Fencing Cost is $945.598 Concrete Cost is $391.119,课堂练习,用类实现计数器抽象数据类型 class CCounter public: CCounter(); void Up(); void Down(); void Zero(); void Value(); private: int a;,课堂练习,设计一个栈类型,考虑下面的数据结构 const int STACK_SIZE=20; class CSta

55、ck public: CStack(); CStack(int sz); CStack(); void push(int e); int pop(); private: int *item; int sp; int size;,课堂练习,private: int *item; int sp; int size;,CPoint类,声明一个CPoint类来描述点对象。 /point.h class CPoint public: CPoint (int x, int y); int XCoord(); int YCoord(); void Move(int xOffset, int yOffset)

56、; private: int X,Y;,CPoint: TPoint(int x,int y) X=x; Y=y; int CPoint: XCoord() return X; int CPoint: YCoord() return Y; void CPoint: Move(int xOffset, int yOffset) X+= xOffset; Y+=yOffset; void main(void) CPoint p(3,4); p.Move(10,20); cout(p.XCoord(), p.XCoord()endl;,类的静态成员,在C语言中有静态变量的概念 局部静态变量 - ,相

57、当于一个局部范围内能够使用的全局变量 对应地,在C+中也有静态成员的概念 静态数据成员 静态成员函数,静态数据成员,用关键字static声明 该类的所有对象维护该成员的同一个拷贝 Class Score char student20; int language; int maths; int history,Public: static int passmark; static int passnum; Score(); Score();,静态数据成员,必须在类外定义和初始化,用(:)来指明所属的类 int Score:passmark = 60; Int Score:passnum = 0;

58、 上述定义和初始化必须放在main()函数的外面来进行,象全局变量一样,int Score:passmark = 60; Int Score:passnum = 0; void main() .,Void main() int Score:passmark = 60; int Score:passnum = 0;,Static int Score:passmark = 60; Static int Score:passnum = 0; void main() .,静态数据成员,静态数据成员在类中仅仅是说明 其内存空间是在初始化语句时进行分配的 在类中说明静态数据成员是不能进行初始化,Class

59、 Score char student20; int language; int maths; int history,Public: static int passmark = 60; static int passnum = 0; Score(); Score();,静态数据成员,静态数据成员可以是公有的,也可以是私有的或保护的 公有静态数据成员可以在类外访问 象普通成员函数一样通过对象来访问,void main() cout Score:passmark endl; .,void main() Score s; cout s.passmark endl;,没有任何理由推荐这种调用方式,因为静态数据成员是独立于类对象的,静态数据成员,如果在类的成员函数中访问静态数据成员时可以将类名和分辨符省略,Class Score char student20; int language; int maths; int history; Public: static int passmark; static int passnum,Score() Score:passmark=60; passn

温馨提示

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

最新文档

评论

0/150

提交评论