在德尔斐, IUnknown 被宣布为:

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

注: 输出参数是无类型

TInterfacedObject 后代,我需要处理 QueryInterface, 所以我可以回报的对象支持该请求的界面:

function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
   if IsEqualGUID(IID, IFooBar) then
   begin
      Obj := (TFooBar.Create(Self) as IFooBar);
      Result := S_OK;
   end
   else
      Result := inherited QueryInterface(IID, {out}Obj);
end;

问题在线:

Obj := (TFooBar.Create(Self) as IFooBar);

德尔菲抱怨:

操作者不适用于这种类型的操作数的

显然我不知道怎么或什么要分配给一个 类型 out 参数。我可以随意尝试的东西,希望编译器将停止抱怨:

Obj := TFooBar.Create(Self);

Obj := Pointer(TFooBar.Create(Self));

Obj := Pointer(TFooBar.Create(Self) as IFooBar);

忽略你所有的代码,我已经写入(如果需要的话):我怎么实现 QueryInterface 在一个对象从后裔 TInterfacedObject?


真正的问题我已经在试图解决可以归结到我想到:

我要替代方法中的一个接口

在相同的方式:

TList = class(TObject)
...
   function GetItem(Index: Integer): Pointer; 
   procedure SetItem(Index: Integer; Value: Pointer);
   property Items[Index: Integer]: Pointer read GetItem write SetItem;
end;

可以在子类:

TStudentList = class(TList)
...
   function GetItem(Index: Integer): TStudent; 
   procedure SetItem(Index: Integer; Value: TStudent);
   property Items[Index: Integer]: TStudent read GetItem write SetItem;
end;

我想那同样有接口:

IFoo = interface(IUnknown)
...
   function GetItem(Index: Variant): Variant; 
   procedure SetItem(Index: Variant; Value: Variant);
   property Items[Index: Variant]: Variant read GetItem write SetItem;
end;

IFooGuidString = interface(IFoo)
...
   function GetItem(Index: TGUID): string ; 
   procedure SetItem(Index: TGUID; Value: string );
   property Items[Index: TGUID]: string read GetItem write SetItem;
end;

问题是,如何我们要开始装我的实施对象有:

TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
   function IFoo.GetItem = FooGetItem;
   procedure IFoo.SetItem = FooSetItem;
   function FooGetItem(Index: Variant): Variant; 
   procedure FooSetItem(Index: Variant; Value: Variant);

   function IFooGuidString.GetItem = FooGuidStringGetItem;
   procedure IFooGuidString.SetItem = FooGuidStringSetItem;
   function FooGuidStringGetItem(Index: TGUID): string ; 
   procedure FooGuidStringSetItem(Index: TGUID; Value: string );
end;

而并不是只有两种方法在 IFoo, 有6.然后如果我要补充另外一个支持的界面:

IFooInt64String = interface(IFoo)
...
   function GetItem(Index: Int64): string ; 
   procedure SetItem(Index: Int64; Value: string );
   property Items[Index: Int64]: string read GetItem write SetItem;
end;


TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
   function IFoo.GetItem = FooGetItem;
   procedure IFoo.SetItem = FooSetItem;
   function FooGetItem(Index: Variant): Variant; 
   procedure FooSetItem(Index: Variant; Value: Variant);

   function IFooGuidString.GetItem = FooGuidStringGetItem;
   procedure IFooGuidString.SetItem = FooGuidStringSetItem;
   function FooGuidStringGetItem(Index: TGUID): string ; 
   procedure FooGuidStringSetItem(Index: TGUID; Value: string );

   function IFooInt64String.GetItem = FooInt64StringGetItem;
   procedure IFooInt64String.SetItem = FooInt64StringSetItem;
   function FooInt64StringGetItem(Index: Int64): string ; 
   procedure FooInt64StringSetItem(Index: Int64; Value: string );
end;

与事情真的难以操作的速度非常快。

有帮助吗?

解决方案

你需要类型铸的 侧分配的发言。这种方式,无类型参数具有类型和编译器知道如何分配给它一个值:

IFooBar(Obj) := TFooBar.Create(Self) as IFooBar;

请注意,你打破的一个 要求COM.如果你查询一个接口,你应该能够查询结果的工具,并始终得到相同的价值:

Foo.QueryInterface(IUnknown, I1);
I1.QueryInterface(IFooBar, B);
B.QueryInterface(IUnknown, I2);
Assert(I1 = I2);

如果你只是想要产生新类型的对象TFooBar,然后给你界的方法产生的那些:

function TFoo.NewFooBar: IFooBar;
begin
  Result := TFooBar.Create(Self) as IFooBar;
end;

其他提示

除了抢劫的讲话,打破这里的规矩,你甚至可以成功地与这一结构:

function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
   if IsEqualGUID(IID, IFooBar) then
      Result := TFooBar.Create(Self).QueryInterface(IID, obj)
   else
      Result := inherited QueryInterface(IID, {out}Obj);
end;

我没有进行调查,但是你可能会得到一些问题参照计数...

根据执行TObject.GetInterface系统。pas我建议:

  Pointer(Obj) := TFooBar.Create(Self);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top