分享
 
 
 

Delphi下的接口编程学习笔记

王朝delphi·作者佚名  2006-05-27
窄屏简体版  字體: |||超大  

1.1 为什么使用接口?

举个例子好了:有这样一个卖票服务,电影院可以卖票,歌剧院可以卖票,客运站也可以卖票,那么我们是否需要把电影院、、歌

剧院和客运站都设计成一个类架构以提供卖票服务?要知道,连经理人都可以卖票,很显然不适合把经理人也包括到卖票服务的继承架构

中,我们需要的只是一个共通的卖票服务。于是,卖票的服务是个接口,电影院、歌剧院什么的只要都遵循这样一个服务定义就能很好地

相互交互和沟通(如果须要的话)。

1.2 如何在Delphi中使用接口

1.2.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这样就行。

说明(2):此GUID可选,如果要实现具有COM特性的接口的话则需要加上,Delphi中对于有GUID的接口在运行时在VMT表的

预定位置生成接口的信息,如接口方法的定义、方法参数定义能详细信息。

说明(3):接口必须实现这三个函数。

1.2.2 接口的实现

接口服务是由类来实现的。

TIntfClass = class(TObject, IMyInterface)

private

FCounter: Integer;

FRefCount: Integer;

public

function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

...

end;

1.2.3 获取接口

a. 使用类型转换。

如:var aIntf: IMyInterface;

begin

aObj := TIntfClass.Create;

try

aIntf := (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)

1.2.4 接口和对象生命期

因为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;

begin

Result := InterlockedDecrement(FRefCount);

end;

1.2.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)

private

FRefCount: Integer;

public

function ConvertToUSD(const iNTD: Integer): Double;

...

end;

implementation

function TImplClass.QueryInterface(const IID: TGUID; out Obj): HResult;

begin

if GetInterface(IID, Obj) then

Result := 0

else

Result := E_NOINTERFACE;

end;

function TImplClass._Release: Integer;

begin

Result := InterlockedDecrement(FRefCount);

if Result = 0 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;

1.2.6 接口和RTTI

Delphi中在VMT-72位移处定义了接口哥格指针:vmtIntfTable = -72。

相关函数:

GetInterfaceCount; //获取接口数量。

GetInterfaceTable; //获取接口表格。

相关结构:

TInterfaceEntry = packed record

IID: TGUID;

VTable: Pointer;

IOffset: Integer;

ImplGetter: Integer;

end;

PInterfaceTable = ^TInterfaceTable;

TInterfaceTable = packed record

EntryCount: Integer;

Entries: array[0..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 = record

name: 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 = record

Flags: TParamFlags;

Name: String;

Info: PTypeInfo;

end;

TTypeInfo = record

Kind: TTypeKind; //数据类型

Name: ShortString; //类型信息的字符串格式

end;

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有