Delphi用DLL来封装对象的技术主要有三种:
用接口实现 用纯虚和抽象类方法实现 用类引用实现
前两种,都是在DLL中生成类实例;第3种通过在调用方生成实例。三种方法的共同局限如下: 调用方只能调用封装类中的virtual方法; 调用方和提供方都必须提供类的描述,接口实现中需要提供接口描述(COM方法例外); 不能创建DLL包含对象的派生类(接口派生除外)。
首先,用接口实现当然包括COM实现,不过由于COM是一种实现接口技术的独立门类,所以在下面说的接口实现中不包括这方面的东西。其次用纯虚和抽象类方法实现,在《Delphi 6 Developer‘s Guide》中提及的inc文件作为公用的头文件,和刘艺在《Delphi面向对象编程思想》中提及的方法本质上是一样的。无非都是为了在调用方加入abstract关键字,而无需方法实现,从而使得编译通过。inc文件的方法是利用宏指令来达到统一处理,不用inc方法是在两处都需要进行描述。 下面用一个例子来展示所以上面提到的集中方法。
调用方主要文件列表为: UnitMain.pas 调用DLL的界面 UnitPublic.pas 第二种方法在调用端的类描述文件 UnitIDest.pas 接口方法和类引用方法的类描述文件 IncDemo.inc 利用inc文件实现的类描述文件 DLL工程主要文件列表为: ProDLLDemo.dpr DLL工程文件 UnitDLLDemo.pas 所有类实现部分的文件 UnitIDest.pas 接口方法和类引用方法的类描述文件 IncDemo.inc 利用inc文件实现的类描述文件 在方法的归纳上如有遗漏,有请指教。
UnitMain.pas 源代码: unit UnitMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, UnitPublic, UnitIDest; {$I IncDemo.inc} // 用于Inc方法的宏指令,如果不是用该方法可去掉上面那行 type TfmMain = class(TForm) Memo1: TMemo; btnUseAbstract: TButton; btnUseReference: TButton; btnUseInterface: TButton; btnUseInc: TButton; procedure btnUseAbstractClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure btnUseInterfaceClick(Sender: TObject); procedure btnUseReferenceClick(Sender: TObject); procedure btnUseIncClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var fmMain: TfmMain; function GetNewspaper: TNewspaper; external 'ProDLLDemo.dll'; function GetCircle: ICircle; external 'ProDLLDemo.dll'; function GetBall: TBallClass; external 'ProDLLDemo.dll'; function GetCar: TCar; external 'ProDLLDemo.dll';
implementation
{$R *.dfm}
procedure TfmMain.FormCreate(Sender: TObject); begin memo1.Lines.Clear; end;
// abstract, virtual 方法示例
procedure TfmMain.btnUseAbstractClick(Sender: TObject); var NewspaperObj: TNewspaper; Info: pchar; i: integer; begin NewspaperObj := GetNewspaper; if NewspaperObj = nil then memo1.Lines.Add('Create newspaper object failed!') else begin try GetMem(Info, 255); i := NewspaperObj.Read(Info); memo1.Lines.Add('Create newspaper object successed!'); memo1.Lines.Add('read : ' + Info + ' return code : ' + inttostr(i)); finally FreeMem(Info); NewspaperObj.Free; end; end; end;
// interface方法示例
procedure TfmMain.btnUseInterfaceClick(Sender: TObject); var CircleObj: ICircle; Info: pchar; i: integer; begin CircleObj := GetCircle; if CircleObj = nil then memo1.Lines.Add('Create circle object failed!') else begin try GetMem(Info, 255); i := CircleObj.Scroll(Info); memo1.Lines.Add('Create circle object successed!'); memo1.Lines.Add('scroll : ' + Info + ' return code : ' + inttostr(i)); finally FreeMem(Info); CircleObj := nil; end; end; end;
// class reference方法示例
procedure TfmMain.btnUseReferenceClick(Sender: TObject); var BallObj : TIBall; Info: pchar; i: integer; begin BallObj := GetBall.Create; if BallObj = nil then memo1.Lines.Add('Create ball object failed!') else begin try GetMem(Info, 255); i := BallObj.Play(Info); memo1.Lines.Add('Create ball object successed!'); memo1.Lines.Add('play : ' + Info + ' return code : ' + inttostr(i)); finally FreeMem(Info); BallObj.Free; end; end; end;
// .inc文件方法示例
procedure TfmMain.btnUseIncClick(Sender: TObject); var CarObj : TCar; Info: pchar; i: integer; begin CarObj := GetCar.Create; if CarObj = nil then memo1.Lines.Add('Create car object failed!') else begin try GetMem(Info, 255); i := CarObj.Run(Info); memo1.Lines.Add('Create car object successed!'); memo1.Lines.Add('car : ' + Info + ' return code : ' + inttostr(i)); finally FreeMem(Info); CarObj.Free; end; end; end; end. UnitPublic.pas源代码: unit UnitPublic; interface type // ----- virtual, abstract的类定义 ----- TPaper = class(TObject); TNewspaper = class(TPaper) public function Read(info : pchar) : integer; virtual; abstract; end; implementation end. UnitIDest.pas源代码: unit UnitIDest; interface type ICircle = interface ['{A971701F-96EC-4201-9266-57F982805B6E}'] function Scroll(Info : pchar) : integer; end; TIBall = class(TObject) public constructor Create; virtual; abstract; destructor Destroy; virtual; abstract; function Play(info : pchar) : integer; virtual; abstract; end; TBallClass = class of TIBall; implementation end. IncDemo.inc源文件: type TCar = class(TObject) public function Run(info: pchar): integer; virtual; {$IFNDEF INCTEST} abstract; {$ENDIF} end; ProDLLDemo.dpr源文件: library ProDLLDemo; uses SysUtils, Classes, UnitDLLDemo in 'UnitDLLDemo.pas', UnitIDest in 'UnitIDest.pas'; {$R *.res} function GetNewspaper : TNewspaper; begin result := TNewspaper.Create; end; function GetCircle : ICircle; begin result := TCircle.Create; end; function GetBall : TBallClass; begin result := TBall; end; function GetCar : TCar; begin result := TCar.Create; end; exports GetNewspaper, GetCircle, GetBall, GetCar; end. UnitDLLDemo.pas源代码: unit UnitDLLDemo; {$DEFINE INCTEST} interface uses Sysutils, UnitIDest; {$I IncDemo.inc} { ----- 利用纯虚和抽象类实现 ----- } type TPaper = class(TObject) end; TNewspaper = class(TPaper) public constructor Create; destructor Destroy; function Read(info: pchar): integer; virtual; end; { ----- 利用接口实现 ----- } type TShape = class(TInterfacedObject) end; TCircle = class(TShape, ICircle) public constructor Create; destructor Destroy; function Scroll(info: pchar): integer; end; { ----- 利用类引用实现 ----- } type TBall = class(TIBall) public constructor Create;override; destructor Destroy;override; function Play(info : pchar) : integer; override; end; implementation { TNewspaper } constructor TNewspaper.Create; begin inherited Create; end; destructor TNewspaper.Destroy; begin inherited; end; function TNewspaper.Read(info: pchar): integer; var str: string; begin if info <> nil then begin str := self.ClassName; strCopy(info, PChar(str)); end; result := 1; end; { TCircle } constructor TCircle.Create; begin inherited Create; end; destructor TCircle.Destroy; begin inherited; end; function TCircle.Scroll(info: pchar): integer; var str: string; begin if info <> nil then begin str := self.ClassName; strCopy(info, PChar(str)); end; result := 2; end; { TBall } constructor TBall.Create; begin // inherited Create; end; destructor TBall.Destroy; begin // inherited; end; function TBall.Play(info: pchar): integer; var str: string; begin if info <> nil then begin str := self.ClassName; strCopy(info, PChar(str)); end; result := 3; end; { ----- 利用Inc文件实现 ----- } function TCar.Run(info: pchar): integer; var str: string; begin if info <> nil then begin str := self.ClassName; strCopy(info, PChar(str)); end; result := 4; end; end. [参考文献]: 1. Delphi面向对象编程思想,第8章,刘艺, 2003.9, 机械工业出版社. 2. Delphi 6 Developer‘s Guide, p209, Steve Teixeira, SAMS, 2001.
|
请发表评论