基于Delphi的接口编程入门.doc_第1页
基于Delphi的接口编程入门.doc_第2页
基于Delphi的接口编程入门.doc_第3页
基于Delphi的接口编程入门.doc_第4页
基于Delphi的接口编程入门.doc_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

基于Delphi的接口编程入门 为什么使用接口?举个例子好了:有这样一个卖票服务,电影院可以卖票,歌剧院可以卖票,客运站也可以卖票,那么我们是否需要把电影院、歌剧院和客运站都设计成一个类架构以提供卖票服务?要知道,连经理人都可以卖票,很显然不适合把经理人也包括到卖票服务的继承架构中,我们需要的只是一个共通的卖票服务。于是,卖票的服务是个接口,电影院、歌剧院什么的只要都遵循这样一个服务定义就能很好地相互交互和沟通(如果须要的话)。如何在Delphi中使用接口 1、声明接口IMyInterface = interface(IInterface) /说明(1)63E072DF-B81E-4734-B3CB-3C23C7FDA8EA /说明(2)function GetName(const str: String): String; stdcall;function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; /说明(3)function _AddRef: Integer; stdcall; /使接口引用数加1。function _Release: Integer; stdcall;/使接口引用数减1,当小于等于0时作释放动作。end;说明(1):如果有继承关系则在括号里填父接口,否则省却,如:IMyInterface = interface这样就行。type IInterface = interface 00000000-0000-0000-C000-000000000046 function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end;说明(2):此GUID(全球唯一标识符)可选,如果要实现具有COM特性的接口的话则需要加上,Delphi中对于有GUID的接口在运行时在VMT表的预定位置生成接口的信息,如接口方法的定义、方法参数定义能详细信息。说明(3):接口必须实现这三个函数。2、接口的实现接口服务是由类来实现的。TIntfClass = class(TObject, /继承唯一的一个T打头的父类IMyInterface) /可继承实现多个I打头的接口privateFCounter: Integer;FRefCount: Integer;public / IMyInterface接口方法的实现function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;.end;3、获取接口a. 使用类型转换。 如:var aIntf: IMyInterface;beginaObj := TIntfClass.Create;tryaIntf := (IMyInterface(aObj);.b. 利用Delphi编译器内建机制。 如:aIntf := aObj。c. 利用对象的QueryInterface方法。如OleCheck(aObj.QueryInterface(IID, aIntf); 只能存取有GUID的COM接口。d. 利用as操作符。使用as操作符必须符合下面条件:1.接口必须明确地指定是从IInterface接口继承下来。2.必须拥有GUID值在Delphi7中接口的实现类还必须是从TInterfacedObject继承下来才行,如:TIntfClass = class(TInterfacedObject, IMyInterface)4、接口和对象生命期 因为Delphi会自行检查接口如果在使用后没有释放而在生成的程序里加上释放代码,但也因这样带来了问题,如下面代码:vari: Integer;aObj: TIntfClass;aIntf: IMyInterface;beginaObj := TIntfclass.Create;tryaIntf := aObj;aIntf.GetName.finallyaIntf := nil;FreeAndNil(aObj);end;上面的代码执行的话会产生存取违规错误,是因为对接口置nil时已释放接口,而FreeAndNil(aObj)会再释放aIntf一次,而在对aIntf置nil时已释放了该对象。解决这个问题只要不让接口干扰对象的生命期就可以了,在Release中只需减引用计数而不做释放的动作。function TIntfClass._Release: Integer;beginResult := InterlockedDecrement(FRefCount);end; 5、接口的委托(Interface Delegation)分为两种:1. 对象接口委托2. 类对象委托。. 对象接口委托,假如已有下面接口定义:IImplInterface = interface(IInterface)function ConvertToUSD(const iNTD: Integer): Double;function ConvertToRMB(const iNTD: Integer): Double;end;接着有一个类实现了该接口:TImplClass = class(TObject, IImplInterface)privateFRefCount: Integer;publicfunction ConvertToUSD(const iNTD: Integer): Double;.end;implementationfunction TImplClass.QueryInterface(const IID: TGUID; out Obj): HResult;beginif GetInterface(IID, Obj) thenResult := 0elseResult := E_NOINTERFACE;end;function TImplClass._Release: Integer;beginResult := InterlockedDecrement(FRefCount);if Result = 0 thenDestroy;end;. .现在有另外一个类TIntfServiceClass要实现IImplInterface接口,不用重新定义,只须使用上面的TImplClass就可以:TIntfServiceClass = class(TObject, IImplInterface)privateFImplService: IImplInterface;/FSrvObj: TImplClass; /如果是用类对象委托的话publicConstructor Create; overload;Destructor Destroy; override;Constructor Create(aClass: TClass); overload;property MyService: IImplInterface read FImplService implements IImplInterface;/ property MyService: TImplClass read FSrvObj implements IImplInterface; /如果是用对象委托的话。end;实现如下:constructor TIntfServiceClass.Create;beginFImplService := TImplClass.Create;end;constructor TIntfServiceclass.Create(aClass: TClass);varinstance: TImplClass;begininstance := TImplClass(aClass.NewInstance);FImplService := instance.Create;end;destructor TIntfServiceClass.Destroy;beginFImplService := nil; /遵照TImplClass使用引用计数来控制对象生命周期,看TImplClass的Destroy实现。inherited;end;6、接口和RTTIDelphi中在VMT-72位移处定义了接口哥格指针:vmtIntfTable = -72。相关函数:GetInterfaceCount; /获取接口数量。GetInterfaceTable; /获取接口表格。相关结构:TInterfaceEntry = packed recordIID: TGUID;VTable: Pointer;IOffset: Integer;ImplGetter: Integer;end;PInterfaceTable = TInterfaceTable;TInterfaceTable = packed recordEntryCount: Integer;Entries: array0.9999 of TInterfaceEntry;end;Self是指向VMT指针的指针,所以:Self.GetInterfaceTable.EntryCount等价于:aPtr := PPointer(Integeer(Pointer(Self) + vmtIntfTable);只要在声明中使用M+/M-指令就能在Delphi中编译出的程序里添加RTTI信息,如:$M+iInvokable = interface(IInterface)$M-接口的RTTI信息由TIntfMetaData记录结构定义: TIntfMetaData = recordname: String; /接口名称UnitName: String; /接口声明的程序单元名称MDA: TIntfMethEntryArray; /储存接口中方法信息的动态数组IID: TGUID; /接口的GUID值Info: PTypeInfo; /描述接口信息的指针AncInfo: PTypeInfo; /描述父代信息的指针NumAnc: Integer; /此接口继承自父代接口的方法数目end;TIntfMethEntryArray的定义如下:typeTCallConv = (ccReg, ccCdecl, ccPascal, ccStdCall, ccSafeCall);TIntfMethEntry = recordName: String; /方法名称CC: TCallConv; /调用惯例Pos: Integer; /方法在接口中的位置ParamCount: Integer; /方法的参数数目ResultInfo: PTypeInfo; /描述方法回传类型的信息指针SelfInfo: PTypeInfo; /描述方法本身的信息指针Params: TIntfParamEntryArray; /描述参数信息的动态数组HasRTTI: Boolean

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论