《第3章 面向对象编程PPT讲稿.ppt》由会员分享,可在线阅读,更多相关《第3章 面向对象编程PPT讲稿.ppt(41页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第3章 面向对象编程第1页,共41页,编辑于2022年,星期一3.1 对象和类对象和类每一个有明确意义和边界的事物都可以看作是一个对象(Object),这些对象有自己的属性,对象与对象之间还有一定的相互关系。例如,日常生活中使用的电视机就可以看作是一个对象,它可以接收微波信号,可以在屏幕上显示微波信号中包含的信息。此外,我们每个人都可以看作是一个对象,每人都有自己的个性:喜欢看电视或不喜欢看电视。我们与电视机之间还具有一定的关系:当按下电源按钮后,电视机才可以接收微波信号;同时,电视节目还可以让我们高兴、失望或者紧张等。我们可以把具有相似特征的事物归为一类,也就是把具有相同属性的对象看成一个类
2、(Class)。比如,所有的电视机可以归成一个“电视机类”,所有的人可以归成一个“人类”。在面向对象的程序分析和设计技术中,“类”就是对具有相同属性和相同操作的一组相似对象的定义。从另一个角度来看,对象就是类的一个实例。第2页,共41页,编辑于2022年,星期一在程序设计阶段,一个非常重要的工作就是按照面向对象的方法去分析所要解决的问题。也就是清楚所要解决的问题中有多少实体,每一个实体所具有的属性,各个实体之间的关系等。然后把具有相同属性和相同操作的实体划分为一个类,明确每个类的属性和方法。一个复杂的问题总是可以分成若干个比较简单的问题,一个复杂的类也往往是有一些比较简单的类组成。在Delph
3、i中,系统已经定义了各种各样的丰富的类,我们可以直接使用它们。在定义类的时候,也可以由这些类的对象组成。一个类是一个数据类型,就像记录一样,是一种数据结构。第3页,共41页,编辑于2022年,星期一此外,一个类的上层可以有父类,下层可以有子类。这种层次结构又叫做继承性,也就是可以在一个基类的基础上派生出一个新类,新类不仅具有基类的属性和方法,而且还可以有自己的一些独特的属性和方法。这样,就可以在不同的类之间共享数据结构和程序代码,减少了冗余代码,增强了系统的健壮性,加快了系统的开发进度,并且使得系统的维护和修改工作变得简单多了。第4页,共41页,编辑于2022年,星期一3.1.1 类的定义在O
4、bject Pascal语言中,类和记录比较相似,也是一个构造类型。定义格式如下:typeclassName=class(ancestorClass)memberListend;其中classname表示新声明类的标识符,ancestorClass表示新声明类的基类,类的名称通常是一个以T开头的标识符,memberList部分是类的成员,第5页,共41页,编辑于2022年,星期一可以声明一些变量和对象,也可以声明一些过程与函数。组成类的成员有三种:数据域、属性和方法。数据域一般是类中使用的各种变量。与记录类型变量相似,类数据域存在于每一个该类的实例中。属性实际上也是类的一个数据域,但是属性还被
5、用于类的接口。用户在声明属性时可以指定属性被赋值或者值被修改时进行的操作。类实例的属性对该实例 以外的程序来说,属性更像一个普通的数据域。例如:定义一个TMyClass类typeTMyClass=class(TObject)end;第6页,共41页,编辑于2022年,星期一3.1.2 数据域类中的数据域就像一个属于某个对象的变量。数据域可以是任何一种类型甚至也可以是一个类的实例。在实际使用中类中的数据域通常都被声明为私有的。如果用户要把数据域声明为类类型,可以像声明其他类型变量一样操作。在定义类时要注意,所有对数据域的声明要在属性和方法的前面。例如:Type TMyClass=class(TO
6、bject)x:integer;/定义一个类的数据整型变量xend;第7页,共41页,编辑于2022年,星期一3.1.3 方法方法(method)是属于某个类的函数或过程。在类中方法的声明被分成两个部分,一个是函数与过程的头部,另一个是函数与过程的定义部分。这种声明方式与函数、过程的前置声明十分类似。但在定义部分的标识符前要加类标识符和“.”来限定隶属关系。例如:Type TMyClass=class(TObject)/在TMyClass类中声明一个方法DoSomething,该方法是一个过程procedure DoSomething;/在TMyClass类中声明一个方法GetSomethin
7、g,该方法是一个函数function GetSomething:String;end;第8页,共41页,编辑于2022年,星期一procedure TMyClass.DoSomething;/方法DoSomething过程的定义beginend;function TMyClass.GetSomething:String;/方法GetSomething函数的定义beginend;方法根据其头部引导字的不同可以分成四种:函数、过程、构造和析构。其中构造和析构是分别用于在使用时创建一个类的对象实例和释放类对象实例。第9页,共41页,编辑于2022年,星期一3.1.4 属性属性(property)是对
8、象状态和行为的特征值,是类中数据的外在表现。外部代码通过属性访问类中的数据。因此属隐藏了类中数据和方法的实现细节。如窗体的Caption属性决定了窗体的标题。属性是类中可以在“读/写”时执行指定方法的数据域;有的属性是可读写(read-write);有的属性只能读不能写,称为只读(read-only)属性。事件事件(event)是基于一种消息处理机制,是系统向窗口发送消息的结果。Delphi的事件是在收到相应的Windows消息后被触发的。如用户单击按钮,就会触发按钮的单击事件。可以为按钮的单击事件编写处理程序。当程序运行时,用户单击按钮,系统就执行该按钮上的用户编写事件处理程序。第10页,共
9、41页,编辑于2022年,星期一3.2 类的特性类的特性第11页,共41页,编辑于2022年,星期一3.2.1 封装与继承在Delphi中,如果不指明父类,则默认的父类为TObject类,也就是直接从TObject类派生出一个新类。TObject类是在System单元中定义的。类的所有成员都有一个标明“能见度”的属性,它们是由保留字private、protected、public、published来说明的。通过这些保留字,可以控制对类中成员的访问权限。每个保留字的具体含义如下:1.private 具有private属性的成员称为私有成员,不能被类所在单元以外的程序访问。也就是说,一个私有的属
10、性不可以在所在模块之外的其他模块中读写,一个私有的方法也不可以在所在模块之外的其他模块中被调用。第12页,共41页,编辑于2022年,星期一2.protected具有protected属性的成员称为保护成员,可以被该类的所有派生类访问,并且成为派生类的私有成员。3.public具有public属性的成员称为公有成员,可以被该类以外的类访问。如果两个类不在同一个单元文件中,则要在uses语句中包括被访问的类所在的单元名称。4.published具有published属性的成员称为发行类型成员,它的访问权限基本与公有成员相同,只是在设计期间也可以被访问。通常发行类型的成员用在组件类的声明中,这样,
11、就可以在对象监视器中访问组件的发行类型的成员。除了在类封装的时候可以限制成员的访问权限外,在后面介绍的单元文件中也可以限制对变量、对象、函数和过程等的访问权限。为了使软件系统具有良好的安全性、健壮性,应该注意这些限制权限的用法。第13页,共41页,编辑于2022年,星期一实例讲解【例3.1】该例说明了类的权限的使用。program Project1;$APPTYPE CONSOLEtype THuman=class/定义一个人类 private Name:String;/姓名 public Age:integer;/年龄 procedure SetName(xm:String);functio
12、n GetName:String;end;第14页,共41页,编辑于2022年,星期一procedure THuman.SetName(xm:String);begin Name:=xm;end;function THuman.GetName:String;begin result:=Name;end;var man:THuman;begin man:=THuman.Create;第15页,共41页,编辑于2022年,星期一man.SetName(张三);writeln(姓名:,man.GetName);man.Age:=20;writeln(年龄:,man.Age);writeln(按下回车
13、键退出。);readln;end.第16页,共41页,编辑于2022年,星期一说明:例程中的THuman类默认从TObject类派生而来,在类中定义了两个私有成员变量Name是字符串型和Age是整型。由于Name是私有的数据,所以不能被类所在单元以外的程序访问。因些我们定义两个公有方法SetName和GetName分别来给Name赋值和得到Name的值。这就体现了类的封装性。而Age是公有的数据,因此可以不需要公有方法来给Age赋值和获得Age赋值。第17页,共41页,编辑于2022年,星期一3.2.2 构造函数和析构函数构造函数和析构函数在完成了类的封装之后,就可以使用这个类了。具体的步骤如
14、下:1)声明类的一个变量。这时可以将类作为一种数据类型来看待。2)调用类的一个特殊函数构造函数来进行一些初始化工作,比如按照类的结构来分配内存资源,完成对象的创建。3)对类的实例对象进行操作、使用。可以修改对象的属性或调用对象的方法。4)使用完毕,调用类的另一个特殊函数析构函数,删除创建的对象,同时释放相应的内存资源等。此外,还可以调用free过程释放对象占用的资源。第18页,共41页,编辑于2022年,星期一构造函数和析构函数是类定义中两个非常重要的函数,它们完成的功能正好相反,它们的定义也比较特殊。在声明了类的一个变量后,并没有实际创建该类的对象,只是定义了一个指向该类对象的指针,有时也称
15、之为类的引用。对象的创建和初始化工作是由类的构造函数来完成的。在类的构造函数中,不仅可以根据类的结构为类的对象分配内存空间,而且还可以打开文件或数据库,读取一些初始数据,或者控制一些设备进行复位等。在定义构造函数的时候,不是使用保留字func tion,而是使用保留字constructor,通常函数名使用Create。如果在定义类的时候没有定义构造函数,则系统会自动为该类生成一个默认的构造函数。构造函数必须使用默认的函数调用约定方式,也就是使用register指令字方式。第19页,共41页,编辑于2022年,星期一我们也可以自定义一个或多个构造函数。自定义的构造函数可以有参数列表,可以重载构造
16、函数。一般在自定义的构造函数的函数体中,在开始部分使用inherited保留字来调用父类的构造函数。如果在创建并初始化对象时,调用构造函数发生错误,则会自动调用析构函数来删除这个没有完成的对象。析构函数的作用是将对象删除并释放相应的内存资源,此外还可以在这之前保存一些数据信息并关闭文件或数据库等,或者对一些设备进行复位并关机。在定义析构函数的时候,使用保留字destructor代替通常函数的function,函数名为Destroy。第20页,共41页,编辑于2022年,星期一如果在定义类的时候没有定义析构函数,则系统会自动为该类生成一个默认的析构函数。析构函数也必须使用默认的函数调用约定方式,
17、也就是使用register指令字方式。我们也可以自定义析构函数。自定义的析构函数在结尾部分使用inherited保留字来调用父类的析构函数。在释放对象占用的资源时也可以使用TObject类的成员过程Free。使用Free过程可以删除一个对象,如果该对象不为nil,则会自动调用析构函数。通常在运行时创建的对象应该调用Free过程来代替析构函数。因为如果对象没有被初始化,则调用析构函数时就会出错,而调用Free过程就没有问题。第21页,共41页,编辑于2022年,星期一实例讲解【例3.2】该例说明了类的封装和使用。program Project1;$APPTYPE CONSOLEtype THum
18、an=class/人类 private Age:integer;/年龄 public Name:String;/姓名 function GetAge:integer;/获取年龄 procedure SetAge(nl:integer);/设置年龄 end;TStudent=class(THuman)/学生类第22页,共41页,编辑于2022年,星期一 public SchoolName:String;/学校名称 procedure ShowInf;/显示学生信息 end;TTeacher=class(THuman)/教师类 public Wage:double;/薪水 constructor
19、Create(gz:double);destructor Destroy;override;end;第23页,共41页,编辑于2022年,星期一function THuman.GetAge:integer;/获取人员的年龄begin Result:=Age;end;procedure THuman.SetAge(nl:integer);begin Age:=nl;/设置人员的年龄end;procedure TStudent.ShowInf;/显示学生的信息begin writeln(姓名:,Name,年龄:,GetAge,学校:,SchoolName);end;第24页,共41页,编辑于202
20、2年,星期一constructor TTeacher.Create(gz:Double);/教师类的构造函数begin inherited Create;/调用父类的构造函数 writeln(调用教师类的构造函数。);Wage:=gz;end;destructor TTeacher.Destroy;/教师类的析构函数begin writeln(姓名为:,Name,的教师类对象被删除。);inherited Destroy;/调用父类的析构函数end;第25页,共41页,编辑于2022年,星期一var S1:TStudent;/声明一个学生类的变量 T1:TTeacher;/声明一个教师类的变量
21、begin S1:=TStudent.Create;/调用默认的构造函数创建对象 S1.Name:=张三;S1.SetAge(19);S1.SchoolName:=某某理工学院;S1.ShowInf;/显示学生信息 S1.Destroy;/调用默认的析构函数第26页,共41页,编辑于2022年,星期一 T1:=TTeacher.Create(1600.50);/调用构造函数创建对象 T1.Name:=陈建辉;T1.Age:=29;/显示教师信息 writeln(姓名:,T1.Name,年龄:,T1.Age,月薪:,T1.Wage);T1.Destroy;/调用自定义的析构函数 writeln(
22、按下回车键退出。);readln;end.第27页,共41页,编辑于2022年,星期一第28页,共41页,编辑于2022年,星期一说明:例程中的THuman类默认从TObject类派生而来,然后它又派生出两个子类:TStudent类和TTeacher类。TStudent类对THuman类进行了功能扩展,又增加了SchoolName属性和ShowInf过程。TTeacher类对THuman类进行了不同的功能扩展,增加了Wage属性。此外,TTeacher类中自定义了构造函数和析构函数。应该注意在自定义的构造函数和析构函数的函数体中,调用构造函数的方法与调用析构函数的方法不同,前者使用的是“类的构
23、造函数”,后者使用的是“对象的析构函数”。第29页,共41页,编辑于2022年,星期一3.2.3 多态性在在Object Pascal语言中定义的类的方法通常是语言中定义的类的方法通常是“静态静态”的,也就是的,也就是在编译和链接阶段就确定了对象方法的调用地址。在编译和链接阶段就确定了对象方法的调用地址。面向对象的程序设计语言还可以在运行时才确定对象方法的调用地面向对象的程序设计语言还可以在运行时才确定对象方法的调用地址,这种调用函数的方式叫做多态性,有时也称为动态联编或滞后址,这种调用函数的方式叫做多态性,有时也称为动态联编或滞后联编。在对象联编。在对象Pascal语言中,多态性是通过虚拟方
24、法或动态方法实语言中,多态性是通过虚拟方法或动态方法实现的。现的。通常,可以将类中的方法定义为下面的三种方式:通常,可以将类中的方法定义为下面的三种方式:静态方法。静态方法。虚拟方法。虚拟方法。动态方法。动态方法。第30页,共41页,编辑于2022年,星期一实例讲解【例【例3.3】该例说明了静态方法】该例说明了静态方法ShowInf的调用情况。的调用情况。program Project1;$APPTYPE CONSOLE typeTHuman=class/人类人类procedure ShowInf;/显示信息显示信息end;TStudent=class(THuman)/学生类学生类proced
25、ure ShowInf;/显示学生信息显示学生信息end;第31页,共41页,编辑于2022年,星期一procedure THuman.ShowInf;/显示调用的是THuman类的ShowInfbeginwriteln(调用THuman.ShowInf);end;procedure TStudent.ShowInf;/显示调用的是T S t u d e n t类的S h o w I n fbeginwriteln(调用TStudent.ShowInf);end;varH1:THuman;/声明一个人类的变量S1:TStudent;/声明一个学生类的变量第32页,共41页,编辑于2022年,星
26、期一beginH1:=THuman.Create;H1.ShowInf;/调用的是THuman类的ShowInfH1.Destroy;H1:=TStudent.Create;H1.ShowInf;/调用的是THuman类的ShowInfTStudent(H1).ShowInf;/调用的是TStudent类的ShowInfH1.Destroy;S1:=TStudent.Create;第33页,共41页,编辑于2022年,星期一S1.ShowInf;/调用的是TStudent类的ShowInfS1.Destroy;writeln(按下回车键退出。);readln;end.第34页,共41页,编辑于
27、2022年,星期一虚拟方法和动态方法也可以在派生类中被重载,通常称为“动态重载”。对象方法具体使用的方法并不是变量声明时指定的类的类型。指明一个方法为虚拟方法或动态方法要使用指令字virtual或dynamic。虚拟方法和动态方法在语意上是等价的,它们的不同主要之处在于运行时方法的调用实现上。虚拟方法调用的速度比较快,而动态方法的代码数量比较少。一般在静态方法无法实现的情况下,可以考虑虚拟方法和动态方法实现动态联编。通常虚拟方法在实现多态性方面效率比较高。如果一个基类派生了很多子类,只是偶尔对方法进行重载,那么使用动态方法比较合适。第35页,共41页,编辑于2022年,星期一实例讲解【例3.4
28、】该例说明了虚拟方法的定义与使用。program Project1;$APPTYPE CONSOLEType THuman=class/人类procedure ShowInf;virtual;end;TStudent=class(THuman)/学生类procedure ShowInf;override;end;TTeacher=class(THuman)/教师类procedure ShowInf;override;end;第36页,共41页,编辑于2022年,星期一procedure THuman.ShowInf;beginwriteln(调用THuman.ShowInf);end;proc
29、edure TStudent.ShowInf;beginwriteln(调用TStudent.ShowInf);end;procedure TTeacher.ShowInf;beginwriteln(调用TTeacher.ShowInf);end;第37页,共41页,编辑于2022年,星期一varH1:THuman;/声明一个人类的变量声明一个人类的变量S1:TStudent;/声明一个学生类的变量声明一个学生类的变量begin H1:=THuman.Create;H1.ShowInf;/调用的是调用的是THuman类的类的ShowInf H1.Destroy;H1:=TStudent.Cre
30、ate;H1.ShowInf;/调用的是调用的是TStudent类的类的ShowInf TTeacher(H1).ShowInf;/调用的是调用的是TStudent类的类的ShowInf H1.Destroy;H1:=TTeacher.Create;H1.ShowInf;/调用的是调用的是TTeacher类的类的ShowInf THuman(H1).ShowInf;/调用的是调用的是TTeacher类的类的ShowInf第38页,共41页,编辑于2022年,星期一 H1.Destroy;S1:=TStudent.Create;S1.ShowInf;/调用的是TStudent类的ShowInf
31、TTeacher(S1).ShowInf;/调用的是TStudent类的ShowInf S1.Destroy;writeln(按下回车键退出。);readln;end.第39页,共41页,编辑于2022年,星期一3.2.4 self关键字方法与过程及函数在定义、实现方式上非常相似。它们之间的区别在于,在实现方法时,方法有一个隐式参数self,它是对当前对象的一个引用。在声明同类的多个对象时,使用self就只对自己的数据进行操作,而不会影响其他兄弟对象。例如:program Project1;$APPTYPE CONSOLEtype THuman=class/定义一个人类 private Name:String;/姓名第40页,共41页,编辑于2022年,星期一 public Age:integer;/年龄 procedure SetName(xm:String);function GetName:String;end;procedure THuman.SetName(xm:String);begin self.Name:=xm;/self表示THuman当前类对象end;function THuman.GetName:String;begin result:=self.Name;end;第41页,共41页,编辑于2022年,星期一
限制150内