gpt4 book ai didi

delphi - 如何检查一个类是否实现了一个接口(interface),并尊重超集?

转载 作者:行者123 更新时间:2023-12-03 15:19:58 25 4
gpt4 key购买 nike

我正在学习 COM 和接口(interface),并有以下实验代码:

type
IA = interface(IInterface)
['{C9C5C992-3F67-48C5-B215-7DCE6A61F0E8}']
end;

IB = interface(IA)
['{F1799437-AD12-471B-8716-F1D93D1692FC}']
end;

IC = interface(IB)
['{01780E8C-C47D-468E-8E42-4BFF3F495D51}']
end;

TBO = class(TInterfacedObject, IB)
end;

procedure TForm1.FormCreate(Sender: TObject);
var
x: TBO;
a: IInterface;
begin
x := TBO.Create;
IInterface(x)._AddRef;

if Assigned(TBO.GetInterfaceEntry(IA)) then memo1.lines.add('GetInterfaceEntry IA: OK'); // Why not?
if Assigned(TBO.GetInterfaceEntry(IB)) then memo1.lines.add('GetInterfaceEntry IB: OK');
if Assigned(TBO.GetInterfaceEntry(IC)) then memo1.lines.add('GetInterfaceEntry IC: OK');

if x.QueryInterface(IA, a)=S_OK then memo1.lines.add('QueryInterface TA: OK'); // Why not?
if x.QueryInterface(IB, a)=S_OK then memo1.lines.add('QueryInterface TB: OK');
if x.QueryInterface(IC, a)=S_OK then memo1.lines.add('QueryInterface TC: OK');

if Supports(TBO, IA) then memo1.lines.add('Supports TA: OK'); // Why not?
if Supports(TBO, IB) then memo1.lines.add('Supports TB: OK');
if Supports(TBO, IC) then memo1.lines.add('Supports TC: OK');

if Supports(x, IA, a) then memo1.lines.add('Supports(2) TA: OK'); // Why not?
if Supports(x, IB, a) then memo1.lines.add('Supports(2) TB: OK');
if Supports(x, IC, a) then memo1.lines.add('Supports(2) TC: OK');
end;

输出:

GetInterfaceEntry IB: OK
QueryInterface TB: OK
Supports TB: OK
Supports(2) TB: OK

但我需要:

GetInterfaceEntry IA: OK
GetInterfaceEntry IB: OK
QueryInterface TA: OK
QueryInterface TB: OK
Supports TA: OK
Supports TB: OK
Supports(2) TA: OK
Supports(2) TB: OK

由于接口(interface)继承,我知道 IBIA 的超集。根据我的理解,由于 TBO 实现了 IB,它自动实现了 IA。但为什么 Supports()QueryInterface()GetInterfaceEntry() 返回 false?

如何查询 TBO 是否直接或间接实现 IA,即通过实现 IA 的超集?我需要两个,一个像 GetInterfaceEntry 这样的静态类函数,一个像 QueryInterface 这样的动态对象引用变体。

最佳答案

Marco Cantù explains here :接口(interface)“继承”与类继承不同,事实上,将其称为接口(interface)扩展可能会更好。

如果我们假设一个类自动实现了一个基接口(interface),就会出现一些严重的异常情况。

考虑:

IA = interface
<guid>
end;
IA1 = interface(IA)
<guid>
end;
IA2 = interface(IA)
<guid>
end;

还有一个聚合 IA1 和 IA2 的类,其中两者都被委托(delegate):

TAggregate = class(TInterfacedObject, IA1, IA2)
private
FIA1: IA1;
FIA2: IA2;
protected
property ImplIA1: IA1 read FIA1 implements IA1;
property ImplIA2: IA2 read FIA2 implements IA2;
end;

现在,如果您询问 TAggregate 实例的 IA 接口(interface),它应该返回哪个实现?

重点是接口(interface)“继承”并不是真正的继承。因此,除非明确地实现该对象,否则该对象不会实现“祖先”接口(interface)。

<小时/>

还有一些其他事情需要观察:

如果将方法 procedure MethodIA; 添加到 IA 接口(interface),并且 do 还显式添加 IA 作为 TAggregate 上的接口(interface),代码无法编译。您会收到错误:

Undeclared indentifier: 'MethodIA'

您必须将 MethodIA 直接添加到类中,或者选择将实现委托(delegate)给 FIA1FIA2 中的哪一个。例如。选择FIA2:

  property ImplIA: IA2 read FIA2 implements IA;

此属性声明显示了 Delphi 识别接口(interface)“is-a”关系的方式。 IE。不是通过实现类,而是通过接口(interface)引用。

注意:即使在编译时,编译器也不会假设类实现了基接口(interface),除非明确声明。

TIA1Implementor = class(TInterfacedObject, IA1)
protected
procedure MethodIA;
end;

var
LImplObj: TIA1Implementor;
LA1: IA1;
LA: IA;
begin
LImplObj := TIA1Implementor.Create;
LA1 := LImplObj; //Valid: TIA1Implementor implements IA1
LA := LImplObj; //Does not compile: TIA1Implementor does not implement IA
LA := LA1; //Valid: IA1 is an extension of IA
end;

在编译时,扩展是已知的,并且将扩展引用分配给它的基础是完全合法的(没有任何强制转换或“支持”检查)。但直接从对象引用赋值则不然。

<小时/>

有趣的是,TypInfo 单元表明接口(interface)类型确实了解其“父”接口(interface)。

PTypeData = ^TTypeData;
TTypeData = packed record
case TTypeKind of
tkInterface: (
IntfParent : PPTypeInfo; { ancestor }
IntfFlags : TIntfFlagsBase;
Guid : TGUID;
IntfUnit : ShortStringBase;
{PropData: TPropData});

但是考虑到上面的讨论,我不确定这些知识在运行时有何用处。我更倾向于编译时检查。

关于delphi - 如何检查一个类是否实现了一个接口(interface),并尊重超集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24705061/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com