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