虚拟方法
虚拟方法在Delphi中利用关键字virtual定义。一个方法被声明为虚拟方法后,在调用时,程序需要动态地确定需要调用的方法。
现在重新定义上面的方法。需要注意的是此处使用了关键字override,表示方法的重载。代码如下所示:
type
TFigure = class
procedure Draw; virtual;
procedure Destroy
end;
procedure Tfigure.Draw;
begin
writeln('现在调用的是TFigure对象');
end;
type
TRectangle = class(TFigure)
procedure Draw; override;
procedure Destroy
end;
procedure TRectAngle.Draw;
begin
writeln('现在调用的是TRectangle对象');
end;
type
TEllipse = class(TFigure)
procedure Draw; override;
procedure Destroy
end;
procedure TEllipse.Draw;
begin
writeln('现在调用的是TEllipse对象');
end;
下面的代码调用上述图形对象的Draw方法:
var
Figure: TFigure;
begin
Figure := TRectangle.Create;
Figure.Draw; // 调用TRectangle.Draw
Figure.Destroy;
Figure := TEllipse.Create;
Figure.Draw; // 调用TEllipse.Draw
Figure.Destroy;
end;
上述代码中,第一次调用Figure.Draw时,当前对象是TRectangle类型;第二次调用Figure.Draw时,当前对象是TEllipse类型。
输出如下:
现在调用的是TRectangle对象
现在调用的是TEllipse对象
动态方法
动态方法利用dynamic关键字实现,它的功能与虚拟方法基本类似,不同主要体现在内部实现。与对象虚拟方法创建入口不同的是,dynamic给方法赋了一个数字,并存储相应代码的地址。动态方法列表只包含新加的和覆盖的方法入口,继承的动态方法的匹配是通过查找每一个祖先的动态方法列表(按与继承“反转的顺序”)来实现,因此动态方法用于处理消息(包括Windows消息)。实际上,消息处理过程的匹配方式与动态方法相同,只是定义方法不同。
动态方法没有对象VMT(Virtal Method Table,虚拟方法表)的入口,它们减少了对象消耗的内存数量。匹配动态方法比匹配一般的虚拟方法慢。因此,如果方法调用很频繁,最好将其定义为虚拟方法。
抽象方法
抽象方法利用关键字abstract实现,如果一个方法定义为抽象,则这个方法不需要在本类中实现。而在它的子类中,可以在重载方法中实现相关功能。
在下面代码中,TFigure对象的Draw方法声明为抽象,所以不需要实现TFigure.Draw方法,在它的子类中,子类数据根据各自不同的需求重载并实现这个方法。
type
TFigure = class
procedure Draw; virtual;abstract;
procedure Destroy
end;
type
TRectangle = class(TFigure)
procedure Draw; override;
procedure Destroy
end;
procedure TRectangle.Draw;
begin
writeln('现在调用的是TRectangle对象');
end;
type
TEllipse = class(TFigure)
procedure Draw; override;
procedure Destroy
end;
procedure TEllipse.Draw;
begin
writeln('现在调用的是TEllipse对象');
end;
如果一个类的抽象方法没有被重载,则这个方法是不能被调用的,否则会产生调用抽象方法的内部Delphi错误。
方法重载
前面已经指出,通过override(方法重载)可以实现多态。方法重载即指多个方法可以享有相同的名字。通过在后代对象中声明一个与祖先对象重名的方法,就可以重载一个方法。如果想使这个方法在后代对象中做和祖先对象一样的工作,但是使用不同的方式,就可以重载这个方法。
如下几种情况将导致重载失败:
(1)祖先类中没有要重载的方法。
(2)要重载的方法在祖先类中被声明为静态方法。
(3)要重载的方法的参数类型或个数与祖先类中不同。
方法继承
Delphi利用关键字inherited实现方法之间的互相继承。
如果inherited关键字后面没有方法名,那么当前方法就继承祖先类中与它同名的方法;如果inherited关键字后面有方法名,则当前方法就继承祖先类中指定的方法。
方法继承经常用在构造方法中,以便子类能够实现祖先类中的一些默认设置。
构造方法
构造方法是一种特殊的方法,它为新对象分配内存并且指向这个新的对象。Delphi中的每个类都有构造方法,用来初始化该类的一个新的对象。
构造函数利用关键字constructor来声明,而构造函数的函数名可以任意选择,但是Delphi中函数名一般采用Create。构造函数可以用多个,但是Delphi建议每个对象只定义一个构造函数。
Delphi在构造函数内部实现的处理过程包括:
(1)首先在内存中开辟一块区域用于存储对象。
(2)然后对这块区域默认初始化设置。初始化,包括有序类型的字段清零,指针类型和类类型的字段设置为Nil,字符串类型的字段清为空等。
(3)执行构造中用户指定的动作。
(4)返回一个新分配的并初始化了的类类型实例。返回值的类型必须就是类的类型。
建立一个对象的实例,需要先调用Create方法,然后构造函数把这个实例赋给一个变量。构造方法不返回任何数据类型,在构造方法的实现中,也可以进行方法重载,如下例所示:
type
TShape = class(TGraphicControl)
private
FPen: TPen;
FBrush: TBrush;
procedure PenChanged(Sender: TObject);
procedure BrushChanged(Sender: TObject);
public
constructor Create(Owner: TComponent); override;
destructor Destroy; override;
...
end;
M
constructor TShape.Create(Owner: TComponent);
begin
inherited Create(Owner); // Initialize inherited parts
Width := 65; // Change inherited properties
Height := 65;
FPen := TPen.Create; // Initialize new fields
FPen.OnChange := PenChanged;
FBrush := TBrush.Create;
FBrush.OnChange := BrushChanged;
end;
上述例子中,TShape 类重载了TGraphicControl的构造函数。在构造函数内部,TShape类首先继承TGraphicControl的默认构造函数,实现一些常规设置,然后通过设置自己的一些特殊参数,实现自己的参数初始化,同时使自己与祖先类有所区别。
又一构造函数实例
delphi的构造函数的定义是:
constructor create;
delphi的析构函数的定义是:
destructor destroy;
析构函数是不能重载的,但是构造函数是可以重载的。
构造函数在重载的时候要在后面加“overload”,例如:
constructor create;overload;
constructor create(i:integer);overload;
注意,只有两个构造函数以上才叫重载,只有一个就不用“overload;”了。
默认的构造函数是:constructor create; 如果有重载的话,那么默认的构造函数后面也要加overload,正象上面的例子一样。
delphi构造函数在类外定义在什么位置呢?在implementation的后面。下面给出一个实例,可以从这个实例中看出构造函数的定义:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyForm1 = class(TForm1) //自定义一个TMyForm1类
public
constructor Create; overload; //构造函数有重载
constructor Create(I: Integer); overload; //重载一个构造函数
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyForm1.Create; //这里定义构造函数
begin
inherited Create(nil); //inherited 表示调用父类的构造函数
end;
constructor TMyForm1.Create(I: Integer);
begin
inherited Create(nil);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
A: TMyForm1;
begin
A := TMyForm1.Create(1);
A.Show;
end;
end.