下例是一个显示两个定义在运行时接口的只读属性的例子
type
TSampleComponent = class(TComponent)
private
FTempCelsius: Integer; { 具体实现是private }
function GetTempFahrenheit: Integer;
public
property TempCelsius: Integer read FTempCelsius; { 属性是public }
property TempFahrenheit: Integer read GetTempFahrenheit;
end;
function GetTempFahrenheit: Integer;
begin
Result := FTempCelsius * div + ;
end;
既然用户在设计时不能改变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;
派送方法
派送(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参数理由是对象已经是指针引用了
返回目录DELPHI基础教程
编辑推荐
Java程序设计培训视频教程
JEE高级框架实战培训视频教程
Visual C++音频/视频技术开发与实战
Oracle索引技术
ORACLEG数据库开发优化指南
Java程序性能优化让你的Java程序更快更稳定
C嵌入式编程设计模式
Android游戏开发实践指南
[] [] [] []