知识大全 基于Delphi的接口编程入门
Posted 知
篇首语:空空的口袋不能阻碍你的未来,空空的脑袋你将永远贫穷。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 基于Delphi的接口编程入门相关的知识,希望对你有一定的参考价值。
基于Delphi的接口编程入门 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
一 为什么使用接口?举个例子好了 有这样一个卖票服务 电影院可以卖票 歌剧院可以卖票 客运站也可以卖票 那么我们是否需要把电影院 歌剧院和客运站都设计成一个类架构以提供卖票服务?要知道 连经理人都可以卖票 很显然不适合把经理人也包括到卖票服务的继承架构中 我们需要的只是一个共通的卖票服务 于是 卖票的服务是个接口 电影院 歌剧院什么的只要都遵循这样一个服务定义就能很好地相互交互和沟通(如果须要的话)
二 如何在Delphi中使用接口
声明接口
IMyInterface = interface(IInterface) //说明( )[ E DF B E B CB C C FDA EA ] //说明( )function GetName(const str: String): String; stdcall;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; //说明( )function _AddRef: Integer; stdcall; //使接口引用数加 function _Release: Integer; stdcall;//使接口引用数减 当小于等于 时作释放动作 end;
说明( ) 如果有继续关系则在括号里填父接口 否则省却 如 IMyInterface = interface这样就行
说明( ) 此GUID可选 如果要实现具有特性的接口的话则需要加上 Delphi中对于有GUID的接口在运行时在VMT表的预定位置生成接口的信息 如接口方法的定义 方法参数定义能详细信息
说明( ) 接口必须实现这三个函数
接口的实现
接口服务是由类来实现的
TIntfClass = class(TObject IMyInterface)private FCounter: Integer; FRefCount: Integer;public function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; end;
获取接口
a 使用类型转换 如
var aIntf: IMyInterface;begin aObj := TIntfClass Create;try aIntf := (IMyInterface(aObj);
b 利用Delphi编译器内建机制 如 aIntf := aObj
c 利用对象的QueryInterface方法 如OleCheck(aObj QueryInterface(IID aIntf)); 只能存取有GUID的接口
d 利用as操作符
使用as操作符必须符合下面条件
接口必须明确地指定是从IInterface接口继承下来
必须拥有GUID值
在Delphi 中接口的实现类还必须是从TInterfacedObject继承下来才行 如
TIntfClass = class(TInterfacedObject IMyInterface)
接口和对象生命期
因为Delphi会自行检查接口如果在使用后没有释放而在生成的程序里加上释放代码 但也因这样带来了问题 如下面代码
var i: Integer; aObj: TIntfClass; aIntf IMyInterface;begin aObj := TIntfclass Create; try aIntf := aObj; aIntf GetName finally aIntf := nil; FreeAndNil(aObj);end;
上面的代码执行的话会产生存取违规错误 是因为对接口置nil时已释放接口 而FreeAndNil(aObj)会再释放aIntf一次 而在对aIntf置nil时已释放了该对象 解决这个问题只要不让接口干扰对象的生命期就可以了 在Release中只需减引用计数而不做释放的动作
function TIntfClass _Release: Integer;beginResult := InterlockedDecrement(FRefCount);end;
接口的委托(Interface Delegation)
分为两种
对象接口委托
类对象委托
对象接口委托 假如已有下面接口定义
IImplInterface = interface(IInterface)function ConvertToUSD(const iNTD: Integer): Double;function ConvertToRMB(const iNTD: Integer): Double;end;
接着有一个类实现了该接口
TImplClass = class(TObject IImplInterface)private FRefCount: Integer;public function ConvertToUSD(const iNTD: Integer): Double; end;
implementation
function TImplClass QueryInterface(const IID: TGUID; out Obj): HResult;beginif GetInterface(IID Obj) then Result := else Result := E_NOINTERFACE;end;
function TImplClass _Release: Integer;begin Result := InterlockedDecrement(FRefCount);if Result = then Destroy;end;
现在有另外一个类TIntfServiceClass要实现IImplInterface接口 不用重新定义 只须使用上面的TImplClass就可以
TIntfServiceClass = class(TObject IImplInterface)private FImplService: IImplInterface; //FSrvObj: TImplClass; //如果是用类对象委托的话public Constructor 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;begin FImplService := TImplClass Create;end;
constructor TIntfServiceclass Create(aClass: TClass);var instance: TImplClass;begin instance := TImplClass(aClass NewInstance); FImplService := instance Create;end;
destructor TIntfServiceClass Destroy;begin FImplService := nil; //遵照TImplClass使用引用计数来控制对象生命周期 看TImplClass的Destroy实现 inherited;end;
接口和RTTI
Delphi中在VMT 位移处定义了接口哥格指针 vmtIntfTable =
相关函数
GetInterfaceCount; //获取接口数量 GetInterfaceTable; //获取接口表格
相关结构
TInterfaceEntry = packed recordIID: TGUID;VTable: Pointer;IOffset: Integer;ImplGetter: Integer;end;
PInterfaceTable = ^TInterfaceTable;TInterfaceTable = packed recordEntryCount: Integer;Entries: array[ ] 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的定义如下
type TCallConv = (ccReg ccCdecl ccPascal ccStdCall ccSafeCall); TIntfMethEntry = record Name: String; //方法名称 CC: TCallConv; //调用惯例 Pos: Integer; //方法在接口中的位置 ParamCount: Integer; //方法的参数数目 ResultInfo: PTypeInfo; //描述方法回传类型的信息指针 SelfInfo: PTypeInfo; //描述方法本身的信息指针 Params: TIntfParamEntryArray; //描述参数信息的动态数组 HasRTTI: Boolean; //这个方法是否拥有RTTI信息的布尔值end;
TIntfMethEntryArray = array of TIntfMethEntry;
参数信息TIntfParamEntry定义
TIntfParamEntry = recordFlags: TParamFlags;Name: String;Info: PTypeInfo;end;
cha138/Article/program/Delphi/201311/24851相关参考
知识大全 使用NetworkInterface类获得网络接口信息
Java网络编程从入门到精通(11):使用NetworkInterface类获得网络接口信息 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理
新手上路:Delphi接口笔记 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!// a:=strin
全面剖析C#接口编程之定义接口 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 从技术上讲接口是一
基于C#的接口基础教程之六 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 继承接口实现 接口具
基于C#的接口基础教程之三 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 第三节定义接口成员
基于C#的接口基础教程之四 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 第四节访问接口 对接
基于C#的接口基础教程之五 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 第五节实现接口 显式
基于C#的接口基础教程之七 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 映射接口 类必须为在
基于C#的接口基础教程之二 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 第二节定义接口 从技
基于C#的接口基础教程之一 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &