- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在学习 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)继承,我知道 IB
是 IA
的超集。根据我的理解,由于 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)给 FIA1
或 FIA2
中的哪一个。例如。选择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/
在C#中,我可以通过base关键字访问基类,在java中,我可以通过super关键字访问它。在delphi中如何做到这一点?假设我有以下代码: type TForm3 = class(TF
在这件事上我已经把头撞到墙上好几次了。所以我希望在正确的方向上得到一点帮助。 我有一张 table ,上面有订单,一张 table 上有火车,一张 table 上有航类,一张 table 上有巴士。每
在 Python 中,假设我有以下代码: class SuperClass(object): def __init__(self, x): self.x = x
我希望这个 subview 扩展到它的父 View 之外,但是父 View 的边框正在切入 subview 。有没有办法防止这种情况? class TheView : UIView { let
我有一个标准的高斯函数,看起来像这样: def gauss_fnc(x, amp, cen, sigma): return amp * np.exp(-(x - cen) ** 2 / (2
例如,我有下一个类,带有有界类型参数: public class ItemContainer { void addItems(List items); } 在另一个带有参数的类中使用: pub
如何将此设置转换为命令? 结果如下: // Manual Compression (see the image above) Compressed Size: 12,647,451 bytes //
请建议在应用继承时如何使用@Wither/@With。 我有一个抽象类Parent和具体的Child。 Child 应该是不可变的。将 @Wither 放在两者上会给我两个错误: 构造函数 Child
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我正在尝试向服务器(虚拟托管)发出 HTTP2 请求,该服务器根据主机 header 值 (SNI) 提供 SSL 证书。 # conn = hyper.HTTP20Connection('h
我有一个应用程序,必须将大约 1300 万行、大约 10 个平均长度的字符串插入到嵌入式 HSQLDB 中。我一直在调整一些东西(批量大小、单线程/多线程、缓存/非缓存表、MVCC 事务、log_si
我想定义一个函数f(x, t::Type)根据 isa(x, t) 是否执行不同的行为.假设我想调用b1(x)如果是,b2(x)除此以外。 我知道我可以像这样在运行时进行动态检查: function
我正在使用 Hyper-V WMI Provider在 Hyper-V 中导入虚拟机,特别是使用 ImportVirtualSystemEx Msvm_VirtualSystemManagementS
这几个星期以来一直困扰着我,我没有结束对它的研究,因为我目前重载并且它让我落后于第一年的 CS (opengl) 大学类(class),这首先让我研究了这个:如何只用一个 for 循环绘制立方体的所有
我正在我的计算机(操作系统:Windows 8)上开发一个 WP8 应用程序。我需要安装一个 VM 才能拥有 linux。同时我需要使用我的 Windows Phone 模拟器。 我下载了 VMWar
我是一名优秀的程序员,十分优秀!