delphi 基础之二 面向对象概念初步

面向对象概念初步

1.类的定义

类的定义分两步:首先在类(单元)的接口(interface)部分说明这个方法.然后在实现部分(implementation)部分编写方法的实现代码.

定义:

type

类名=class(父类名)

数据域说明;      //类内部使用变量/常量的声明;

方法说明首部;

end;

实现代码:

procedure 类名.方法(参数);

实现代码;

end;

2.创建对象及对象成员的引用

创建对象分两步:

首先声明对象,语法格式为 var 类名;//此时对象名还只是个指针,没分配到内存。

然后调用create 分配内存 语法格式为  对象名:=类名.create。

对象中数据域(C++中的数据成员)和方法的引用 语法如下:

对象.数据域;

对象.方法;

释放对象 对象.free;

3.类的封装

类的每个成员都有一个称为可见性的属性,我们用下面的关键字之一来表示它:private、protected、 public、published 和 automated

类的的数据域(数据成员):

1)Fields  (字段)

字段就像属于对象的一个变量,它可以是任何类型,包括类类型 (也就是说,字段可以存储对象的引用)。 字段通常具有private 属性。

2)方法:

(1)方法的类型

对象的方法能定义成静态( static )、虚拟( virtual )、动态( dynamic)或消息处理(message )。

1. 静态方法

静态方法是方法的缺省类型,对它就像对通常的过程和函数那样调用。编译器知道这些方法的地址,所以调用一个静态方法时它能把运行信息静态地链接进可执行文件。 静态方法执行的速度最快,但它们却不能被覆盖来支持多态性。

2. 虚拟方法(v i r t u a l)

虚拟方法和静态方法的调用方式相同。由于虚拟方法能被覆盖,在代码中调用一个指定的虚拟方法时编译器并不知道它的地址。因此,编译器通过建立虚拟方法表 ( V M T )来查找在运行时的函数地址。所有的虚拟方法在运行时通过V M T来调度,一个对象的V M T表中除了自己定义的虚拟方法外,还有它的祖先的所有的虚拟方法,因此虚拟方法比动态方法用的内存要多,但它执行得比较快。(速度优化)

{虚拟方法还有一种特例,即抽象方法:例如

    procedure One;override;abstract;

在One方法后面,不但有override关键字,还多了一个abstract关键字(意为抽象)。这种方法称为抽象方法(在C++中称为纯虚拟函数)。含有抽象方法的类称为抽象类。抽象方法的独特之处在于,它只有声明,而根本没有实现部分,如果你企图调用一个对象的抽象方法,你将得到一个异常。只有当这个类的派生类重载并实现了该方法之后,它才能够被调用。(在C++中,甚至根本就不能建立一个抽象类的实例。)

既然如此,那么这种抽象方法又有什么用呢?

抽象方法本身不能够做任何事情,必须在子类中被重载并实现,才能够完成有意义的工作。但抽象方法的存在,相当于为父类留下了一个接口,当程序将一个子类的对象赋予父类的变量时,父类的变量就可以调用这个方法,当然此时它运行的是相应的子类中重载该方法的代码。如果没有这个抽象方法,父类的变量就不能调用它,因为它不能调用一个只在子类中存在、而在父类中不存在的方法!

3. 动态方法 (d y n a m i c)

动态方法跟虚拟方法基本相似,只是它们的调度系统不同。编译器为每一个动态方法指定一个独一无二的数字,用这个数字和动态方法的地址构造一个动态方法表 ( D M T )。不像V M T表,在D M T表中仅有它声明的动态方法,并且这个方法需要祖先的D M T表来访问它其余的动态方法。正因为这样,动态方法比虚拟方法用的内存要少,但执行起来较慢,因为有可能要到祖先对象的D M T中查找动态方法。(代码大小优化)

4. 消息处理方法 (message)

在关键字m e s s a g e后面的值指明了这个方法要响应的消息。用消息处理方法来响应windows的消息,这样就不用直接来调用它。。声明方法时,通过包含message指示字创建,并在message后面跟一个介于+1~49151之间的整数常量,体指定消息的号码(ID)。一个message方法必须具有一个单一var参数的过程。例

Typt

Ttextbox=class(Tcustomcontrol)

Private WMChar(var Message:TWMChar);message WM_CHAR;

Endl;

(2)方法的覆盖

在Object Pascal覆盖一个方法用来实现O O P的多态性概念。通过覆盖使一方法在不同的派生类间表现出不同的行为。Object Pascal 中能被覆盖的方法是在声明时被标识为v i r t u a l或d y n a m i c的方法。为 了覆盖一个方法,在派生类的声明中用o v e r r i d e代替v i r t u a l或d y n a m i c 。如果不含override关键字,如果子类声明和父类相同的方法,则视为新建。

T1=class

Procedure Draw;virtual;

End;

T2=calss(T1)

Procedure Draw;override;

End;

(3)方法的重载

所有方法都支持重载。重载后,子类可以含有和祖先类的方法具有不同参数的方法,它只是重载了该方法,并没覆盖它,调用时编译器依靠参数决定到底调用哪一个。能重载的方法必须用o v e r l o a d指示符标识出来。若要重载的是虚方法则需要使用reintroduce指示字。

如 (重载虚方法)

type

T1=class(Tobject)

Procedure test(I:integer);virtual;

End;

T2=calss(T1)

Procedure Test(S:string);reintroduce;oveload;;

End;

(4)方法的继承

例如,你如果使用以下代码:

  type

  TMyClass = class

  procedure One;virtual;

  end;

  

  type

  TNewClass = class(TMyClass)

  procedure One;override;

  end;

  

  procedure TMyclass.One;virtual;

  begin

  ShowMessage(´调用了TMyclass的方法!´);

  end;

  

  procedure TNewClass.One; override;

  begin

  Inherited;

  ShowMessage(´调用了TNewClass的方法!´);

  end;

  

  可以看到,从TMyClass派生了一个新类TNewClass。这两个类都声明了一个名字相同的方法One。所不同的是,在TMyClass中,One方法后面多了一个Virtual关键 字,表示这个方法是一个虚拟方法(Virtual Method)。而在TNewClass中,One方 法后面多了一个Override关键字,表示该方法进行了重载(Override)。重载技术能够实现许多特殊的功能。

让我们来仔细分析它们的实现部分。在TMyclass.One方法的实现部分,调用ShowMessage过程弹出一个对话框,说明该方法已被调用;这里没有任何特别的地方。在TNewClass.One方法中,出现了一条以前从未出现过的语句:

Inherited;

这个词的中文意思是“继承”。我们暂时不要去涉及到太过复杂的OOP概念,只要知道这条语句的功能就是了。它的功能是调用基类中相同的虚拟方法中的代码。

 那么程序将弹出两次对话框,第一次是调用TMyclass类中的One方法,第二次才是TNewClass.One方法中的代码。

重载技术使得我们不但可以在派生类中添加基类没有的数据和方法,而且可以非常方便地继承基类中原有方法的代码,只需要简单地加入Inherited就可以了。如果你不加入Inherited语句,那么基类的相应方法将被新的方法覆盖掉。

(4)方法的构造函数和析构函数

Constructors Create;

Destructor Destroy;

使用 对象,Create;

对象.Destroy;(最好使用 对象.free)

3)属性

普通属性

我们在delphi的类中常常能看到这样的代码:

propert property 属性名 类型名 read 字符串1 write 字符串2

例如:

property Left: Integer read FLeft write SetLeft;

我们在private中看到申明:

procedure SetLeft(Value: Integer);(方法)

和如下代码实现:

procedure TControl.SetLeft(Value: Integer);

begin

SetBounds(Value, FTop, FWidth, FHeight);

Include(FScalingFlags, sfLeft);

end;

如果你写了如下代码改变left:control1.left:=23,那么程序调用了函数SetLeft(23),SetBounds是改变区域的函数,这里你就明白了它封装了的好处,每次你改变left时它就会根据新的left而改变区域的大小,这个函数同时也改变了Fleft的大小。

这样外部就看起来只是通过赋值运算来改变了该属性的值。Read和write可以是变量,或者是函数,取决于你的设计。

你当然可以这样写:

propert property 属性名 类型名 read 变量1(函数) write 变量2(函数)。

变量1和变量2可以是相同的。你也可以这样

propert property 属性名 类型名 read 方法1 write 方法2。

任你组合。但是有2点要注意:

1.命名规则最好按习惯来,易于阅读。

2. 如果是变量,那么类型要和属性的类型一致,如果是方法,那么入口参数要和属性的类型一致。

声明部分:

Type

Tdog=calss

Private

Color:string;

Function Getcolor(x:string);

Procedure Setetcolor(x:string)

Public

Property x:string read Getcolor write setcoler;

End;

实现部分:

Fenction Tdog.Getcolor :string;

Begin

Result:=color;

End;

Procedure Tdog.setcoler(value:string)

Begin

Color:=value;

End;

事件属性Tevent

我们常常使用组件的事件属性,比方说click事件,可是我们很难从表面看出它是如何调用的呢,如何触发的呢。下面我来给你解答。

我们在属性管理器object inspector中看到event页onclick右边对应了一个方法的名字。我们其实可以这样给一个组件的事件对应上一个出来方法。以一个form为例子Form1. OnMouseDown:=‘你的方法‘。注意方法的入口参数有讲究,这里是(Sender:TObject)

我们还是一tcontrol为例子,我们找到这段代码:

property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;跟上面讲的类似,不过这里有个特殊的类型,TNOtifyEvent,是个事件类型,我们找到它的申明:

TMouseEvent = procedure(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer) of object;

可以看到,它其实就是个函数,但是蓝色部分把入口参数限定了。那么我们通过赋值Form1. OnMouseDown:=‘你的方法‘,就对应了OnMouseDown的方法。然后我们只要写了一段拦截鼠标消息的函数,在里面直接或间接调用FonMouseDown,那么就把消息和处理函数对应上去了。这里它间接调用的层数比较多,讲起来比较费时间,涉及到Message类型,建议大家去看下李维的书。

以下附上间接调用过程,其实还要很多消息发生时也间接调用了,就不一一举出来了:(

procedure WMRButtonDblClk(var Message: TWMRButtonDblClk); message WM_RBUTTONDBLCLK;//拦截消息的函数

procedure TControl.WMRButtonDblClk(var Message: TWMRButtonDblClk);

begin

inherited;

DoMouseDown(Message, mbRight, [ssDouble]);

end;

procedure DoMouseDown(var Message: TWMMouse; Button: TMouseButton;

Shift: TShiftState);

procedure TControl.DoMouseDown(var Message: TWMMouse; Button: TMouseButton;

Shift: TShiftState);

begin

if not (csNoStdEvents in ControlStyle) then

with Message do

if (Width > 32768) or (Height > 32768) then

with CalcCursorPos do

MouseDown(Button, KeysToShiftState(Keys) + Shift, X, Y)

else

MouseDown(Button, KeysToShiftState(Keys) + Shift, Message.XPos, Message.YPos);

end;

procedure MouseDown(Button: TMouseButton; Shift: TShiftState;

X, Y: Integer); dynamic;

procedure TControl.MouseDown(Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);

end;

好处:

如果你多写自己的类,你会发现这样做是多么的方便, delphi你都只是调用contol1.text来访问,control1.text:=’某字符串’来修改它的值。

而在处理消息方面,基类把onclick,onmousedown这样的属性申明为protected,如果你要使用,可以申明为published就可以出现在object inspector里面,然后方便的写处理方法,你也可以不公开,而在ctreate函数中给它赋值,而不用像java那样,写listener那么复杂。

5.类的多态

虚方法和动态方法通过覆盖和重载技术实现多态。

6.类的继承

7.类方法

类方法是作用在类而不是对象上面的方法(不同于构造函数)。类方法的定义必须以关键字class 开始,

比如,

type

TFigure = class

public

class function Supports(Operation: string): Boolean; virtual;

class procedure GetInfo(var Info: TFigureInfo); virtual;

...

end;

类方法的定义部分也必须以 class 开始,比如,

class procedure TFigure.GetInfo(var Info: TFigureInfo);

begin

...

end;

在类方法的定义部分,Self 表示调用方法的类

类方法既可以通过类引用来调用,也可以使用对象,当使用后者时, Self 值等于对象所属的类。

7.Self参数:

Self是指所编的程序范围是在哪一个类中,Delphi中大都在窗体范围内编程,因此,Self即指窗体,假如在编写一个类或是一个组件,则Self指该类或该组件.我们在过程和函数的声明中可以看出Self是代表哪个组件,即Self代表"."号之前的组件.另外应注重,Self只能用在类方法中,而不能用在过程或函数中.

时间: 2024-10-28 20:39:36

delphi 基础之二 面向对象概念初步的相关文章

python基础8之面向对象概念介绍

一丶概念 1.面向对象编程 OOP(Object-Oriented Programming)编程是利用"类"和"对象"来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容. 2.Class类 一个类即是对一类拥有相同属性的对象的抽象.蓝图.原型.在类中定义了这些对象的都具备的属性(variable

Java基础教程(4)--面向对象概念

??如果你之前从来没有使用过面向对象编程语言,那么在学习Java之前需要先理解几个有关面向对象编程的基本概念.这篇教程将会向你介绍对象.类.集成.接口和包的概念,以及这些概念是如何与现实世界相关联,并介绍这些概念在Java语言中的体现. 一.对象 ??对象将状态和行为绑定在一起,它可以被用来模拟你能列举出的现实世界中的任何实体.这一小节将会解释如何在对象中表示状态和行为,介绍封装的概念,并解释这种软件设计方式的好处. ??对象是理解面向对象技术的关键.环顾四周,你会发现许多现实世界中的对象:狗.

java基础复习二——面向对象一

面向对象三大特性:封装,继承,多态 类:对象的蓝图,生成对象的模板,是对一类事物的描述,是抽象的概念上的定义 对象:是实际存在的该类事物的每个个体,也称为实例 类之间三种关系:依赖关系(uses-a),聚集关系(has-a),继承关系(is-a) 面向对象: 1.将复杂的事情简单化 2.将以前的过程中的执行者,变成了指挥者 3.这种思想符合现在人们思考习惯的一种思想 匿名对象使用场景:1.当对方法只进行一次调用时: 成员: 1.成员变量:事物的属性 2.成员函数:事物的行为 注意:属性是用于存储

IOS基础之 (二) 面向对象思想

编写Objective-C程序时,要使用Foundation框架. 什么是框架? 框架(framework)是由很多类(class)组成的库,可以用来编写程序. 对象(Object) 对象可以保存数据,还可以包含一组函数. 函数可以使用对象所包保存的数据. 向对象发送某个消息(message), 可以出发响应的函数. 这类由消息出发的函数称为方法(method). OC是一门弱语法. 一 创建第一个Objective-C 程序 创建一个项目,Create a new Xcode project

基础笔记二 面向对象编程

对象的三大特性 (1)封装,类是最小单元的封装,封装后,其他人直接使用dll 保证了代码的安全性 (2)继承: .net 类库用的多,实际开发中用的不多,用接口多 (抽象类等用的不多) (3)多态:重载(编译时多态),和重写(运行时多态),用的也不多,不能随便使用 1. 类与对象的基本概念 (1)类是一个模块,对象就是模板new出的实例(具体的东西) 2. 类的编写有什么具体的方法和技巧 (ps:需要长期的体会,积累和经验总结) 原文地址:https://www.cnblogs.com/haig

【Java面向对象基础(二)】细说String、StringBuffer和StringBuilder

[喵"的Android之路][基础篇(二)][Java面向对象基础]细说String.StringBuffer和StringBuilder 1.String String是Java中的一个final类,主要用于字符串的处理. 1.1 不可变性 String内的字符串是不可变的,每一次修改都会重新生成一个新的String对象实例. 例: 1 // 在堆中会创建一个"Hello"字符串实例,把地址赋给对象a 2 String a = new String("Hello&

(转)面向对象编程初步

1 class Hand: 2 pass 3 class Foot: 4 pass 5 class Trunk: 6 pass 7 class Head: 8 pass 9 10 class Person: 11 def __init__(self,id_num,name,hand,foot,trunk,head): 12 self.id_num=id_num 13 self.name=name 14 self.hand=Hand() 15 self.foot=Foot() 16 self.tr

java 基础(二)

java 基础(二)java 基础(二) 2016-2-1 by Damon 61. 编写多线程程序有几种实现方式 Java 5以前实现多线程有两种实现方法:一种是继承Thread类:另一种是实现Runnable接口.两种方式都要通过重写run()方法来定义线程的行为,推荐使用后者,因为Java中的继承是单继承,一个类有一个父类,如果继承了Thread类就无法再继承其他类了,显然使用Runnable接口更为灵活. 补充:Java 5以后创建线程还有第三种方式:实现Callable接口,该接口中的

单片机教程.指针的基础与1602液晶的初步认识

指针的基础与1602液晶的初步认识 我们在上C语言课的时候,学到指针,每一位教C语言的老师都会告诉我们一句:指针是C语言的灵魂.由此可见,指针是否学会是判断一个人是否真正学会C语言的重要指标之一,但是很多同学只知道其重要性,却没学会其灵活性. 简单的程序,100来行代码,不需要指针我们可以轻松搞定,但是当代码写到几千上万行甚至更多的时候,利用指针就可以直接而快速的处理内存中的各种数据结构中的数据,特别是数组.字符串和内存的动态分配等,它为函数之间各类数据传递提供了简洁便利的方法.说了这么多作用估