Por que minha classe implementa interfaces filho, mas não seus pais?
Eu encontrei um (pelo menos para mim) comportamento inesperado ao usar a herança de interface no Delphi.
Eu tenho essa hierarquia simples de classe e interface:
+---------------+
| << IMyBase >> |
+---------------+
^
|
+---------------+
| << IMyIntf >> |
+---------------+
^
|
+---------+
| TMyObj |
+---------+
Eu queria declarar uma variável do tipoIMyBase
. Crie umTMyObj
e atribuí-lo à minha variável. IHMO, essa é uma prática normal de POO. Mas aconteceu que não compila.
Eu também tentei declarar uma variável do tipoIMyIntf
e verifique se ele suportaIMyBase
, IMHO deve apoiá-lo, mas não.
Aqui está um código de teste simples:
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.
Como você pode ver, tenho uma estrutura de classe / interface válida. mas algumas partes não são compiladas. e alguns não são executados conforme o esperado.
Porqueb := TMyObj.Create;
dar um erro de tipo incompatível?PorqueSupports(i, IMyBase, b)
retornafalse
?Existe outra maneira (melhor) de resolver esse problema? sem um elenco duro sem cheque? (if i is IMyBase
não funciona, porque as interfaces não suportamis
operador.)Este comportamento é válido para Pascal / Delphi ou é um bug? Na minha humilde opiniãoSupports()
deve retornartrue
. eTMyObj
deve ser um válidoIMyBase
(e, portanto, podem ser atribuídos).