Welcome

首页 / 软件开发 / Delphi / 第十九章-Delphi自定义部件开发(一)(4)

第十九章-Delphi自定义部件开发(一)(4)2007-05-07既然用户在设计时不能改变public部分的属性的值,那么该类属性就不能出现在Object Inspector窗口中。

⑷ 定义设计时接口

将对象的某部分声明为published,该部分也即为public且产生运行时类型信息。但只有published部分定义的属性可显示在Object Inspector窗口中。对象的published部分定义了对象的设计时接口。设计时接口包含了用户想在设计时定制的一切特征。

下面是一个published属性的例子,因为它是published,因此可以出现在Object Inspector窗口:

TSampleComponent = class(TComponent)

private

FTemperature: Integer; { 具体实现是 private }

published

property Temperature: Integer read FTemperature write FTemperature; { 可写的 }

end;

3. 派送方法

派送(Dispatch)这个概念是用来描述当调用方法时,你的应用程序怎样决定执行什么样的代码,当你编写调用对象的代码时,看上去与任何其它过程或函数调用没什么不同,但对象有三种不同的派送方法的方式。

这三种派送方法的类型是:

● 静态的

● 虚拟的

● 动态的

虚方法和动态方法的工作方式相同,但实现不同。两者都与静态方法相当不同。理解各种不同的派送方法对创建部件是很有用的。

⑴ 静态方法:

如果没有特殊声明,所有的对象方法都是静态的.。静态方法的工作方式正如一般的过程和函数调用。在编译时,编译器决定方法地址,并与方法联接。

静态方法的基本好处是派送相当快。因为由编译器决定方法的临时地址,并直接与方法相联。虚方法和动态方法则相反,用间接的方法在运行时查找方法的地址,这将花较长的时间。

静态方法的另一个不同之处是当被另一类型继承时不做任何改变,这就是说如果你声明了一个包含静态方法的对象,然后从该对象继承新的对象,则该后代对象享有与祖先对象相同的方法地址,因此,不管实际对象是谁,静态方法都完成相同的工作。

你不能覆盖静态方法,在后代对象中声明相同名称的静态方法都将取代祖先对象方法。

在下列代码中,第一个部件声明了两静态方法,第二个部件,声明了相同名字的方法取代第一个部件的方法。

type

TFirstComponent = class(TComponent)

procedure Move;

procedure Flash;

end;

TSecondComponent = class(TFirstComponent)

procedure Move; { 尽管有相同的声明,但与继承的方法不同 }

function Flash(HowOften: Integer): Integer; { 同Move方法一样 }

end;

⑵ 虚方法

调用虚方法与调用任何其它方法一样,但派送机制有所不同。虚方法支持在后代对象中重定义方法,但调用方法完全相同,虚方法的地址不是在编译时决定,而是在运行时才查找方法的地址。

为声明一个新的方法,在方法声明后增加virtual指令。方法声明中的virtual指令在对象虚拟方法表(VMT)中创建一个入口,该虚拟方法表保存对象类所有虚有拟方法的地址。

当你从已有对象获得新的对象,新对象得到自己的VMT,它包含所有的祖先对象的VMT入口,再增加在新对象中声明的虚拟方法。后代对象能覆盖任何继承的虚拟方法。

覆盖一个方法是扩展它,而不是取代它。后代对象可以重定义和重实现在祖先对象中声明的任何方法。但无法覆盖一个静态方法。覆盖一个方法,要在方法声明的结尾增加override指令,在下列情况,使用override将产生编译错误:

● 祖先对象中不存在该方法

● 祖先对象中相同方法是静态的

● 声明与祖先对象的(如名字、参数)不匹配

下列代码演示两个简单的部件。第一个部件声明了三个方法,每一个使用不同的派送方式,第二个部件继承第一个部件,取代了静态方法,覆盖了虚拟方法和动态方法。

type

TFirstComponent = class(TCustomControl)

procedure Move; { 静态方法 }

procedure Flash; virtual; { 虚 方 法 }

procedure Beep; dynamic; { 动态虚拟方法 }

end;

TSecondComponent = class(TFirstComponent)

procedure Move; { 声明了新的方法 }

procedure Flash; override; { 覆盖继承的方法 }

procedure Beep; override; { 覆盖继承的方法 }

end;

⑶ 动态方法

动态方法是稍微不同于虚拟方法的派送机制。因为动态方法没有对象VMT的入口,它们减少了对象消耗的内存数量。派送动态方法比派送一般的虚拟方法慢。因此,如果方法调用很频繁,你最好将其定义为虚方法。

定义动态方法时,在方法声明后面增加dynamic指令。

与对象虚拟方法创建入口不同的是dynamic给方法赋了一数字,并存储相应代码的地址,动态方法列表只包含新加的和覆盖的方法入口,继承的动态方法的派送是通过查找每一个祖先的动态方法列表(按与继承“反转的顺序”),因此动态方法用于处理消息(包括Windows消息)。实际上,消息处理过程的派送方式与动态方法相同,只是定义方法不同

⑷ 对象与指针

在Object Pascal中,对象实际上是指针。编译器自动地为程序创建对象指针,因此在大多数情况下,你不需要考虑对象是指针。但当你将对象作为参数传递时,这就很重要了。通常,传递对象是按值而非按引用,也就是说,将对象声明为过程的参数时,你不能用var参数,理由是对象已经是指针引用了。