lin*_*luk 10 delphi inheritance interface
在Delphi中使用接口继承时,我发现了(至少对我而言)意外行为.
我有这个简单的类和接口层次结构:
+---------------+
| << IMyBase >> |
+---------------+
^
|
+---------------+
| << IMyIntf >> |
+---------------+
^
|
+---------+
| TMyObj |
+---------+
Run Code Online (Sandbox Code Playgroud)
我想声明一个类型的变量IMyBase.创建一个TMyObj并将其分配给我的变量.IHMO这是正常的OOP练习.但事实证明它没有编译.
我也尝试声明一个类型的变量IMyIntf并检查它是否支持IMyBase,恕我直言它应该支持它,但事实并非如此.
这是一个简单的测试代码:
program interface_inheritance;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
IMyBase = interface
['{CC7C61B8-3FBA-481F-AF0D-A93C603B5202}']
procedure Hello;
end;
IMyIntf = interface(IMyBase)
['{01CE01D9-A753-431C-A30E-64BAEC6C4E26}']
//
end;
TMyObj = class(TInterfacedObject, IMyIntf)
procedure Hello;
end;
{ TMyObj }
procedure TMyObj.Hello;
begin
Writeln('Hello World');
end;
var
b: IMyBase;
i: IMyIntf;
begin
(* // Compile Error E2010
b := TMyObj.Create;
b.Hello;*)
// Does not work as Expected
// Does not call Hello()
i := TMyObj.Create;
if Supports(i, IMyBase, b) then begin
// Why does i not support IMyBase ??
b.Hello;
end;
// Works but unsafe!
// Hard cast, without check.
i := TMyObj.Create;
b := IMyBase(i);
b.Hello;
// Works, of course!
i := TMyObj.Create;
i.Hello;
Readln;
end.
Run Code Online (Sandbox Code Playgroud)
如您所见,我有一个有效的类/接口结构.但有些部分不能编译.有些不按预期执行.
b := TMyObj.Create;出现不兼容的类型错误?Supports(i, IMyBase, b)回报false?if i is IMyBase不起作用,因为接口不支持is运算符.)这是有效的Pascal/Delphi行为还是错误?恕我直言Supports()应该回来true.并且TMyObj应该是有效的IMyBase(因此可以分配).
Dav*_*nan 10
这可能看起来有点反直觉,但是你的类必须声明它也实现了父接口.您的类声明必须如下:
TMyObj = class(TInterfacedObject, IMyBase, IMyIntf)
Run Code Online (Sandbox Code Playgroud)
前Borland工程师Danny Thorpe在回答相关问题时解释了这种行为背后的理由:
如果实现类没有声明它支持继承的接口,那么该类将不会与继承接口的变量进行赋值兼容.您发布的代码示例应该可以正常工作(使用IChild接口),但是如果您尝试从TMyClass的实例分配给IParent变量,那么您将遇到麻烦.
原因是因为COM和ActiveX允许实现实现后代接口(您的IChild)但拒绝该接口的祖先(IParent).由于Delphi接口旨在与COM兼容,因此这个愚蠢的工件来自于此.