[fpc-devel] Managed Types, Undefined Bhaviour
Thorsten Engler
thorsten.engler at gmx.net
Fri Jun 29 16:37:10 CEST 2018
> -----Original Message-----
> From: fpc-devel <fpc-devel-bounces at lists.freepascal.org> On Behalf Of
> Martok
> Sent: Friday, 29 June 2018 23:55
> To: fpc-devel at lists.freepascal.org
> Interface functions are always virtual and implemented by the
> actually instantiated class. The "override" keyword is neither
> allowed nor needed,
Without having looked the particular code this thread is about, that statement, at least how I interpret it, is wrong.
The specific functions that implement an interface get baked into the class at the moment when the interface is defined as part of the class. This results in important differences in behaviour, depending if methods (in the class) are defined as virtual or not, and if a derived class redeclares an interface already declared on an ancestor or not.
I've only tried the following code (which demonstrates this) in Delphi, but would assume FPC to produce the same result (otherwise there is bound to be a lot of Delphi code which produces subtly different outcomes when compiled with FPC).
program IntfImplDetails;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
IFoo = interface(IInterface)
['{E9A12596-8F61-4CF1-A09A-266D56BD837D}']
procedure Foo;
end;
IBar = interface(IFoo)
['{6782527D-431E-49F4-89D0-DCF871BE63A3}']
procedure Bar;
end;
TFoo = class(TInterfacedObject, IFoo)
protected
procedure Foo;
end;
TFooBar = class(TFoo, IBar)
protected
procedure Bar;
procedure Foo;
end;
TFooBarToo = class(TFooBar, IFoo)
protected
procedure Bar;
procedure Foo;
end;
TVirtFoo = class(TInterfacedObject, IFoo)
protected
procedure Foo; virtual;
end;
TVirtFooBar = class(TVirtFoo, IBar)
protected
procedure Bar;
procedure Foo; override;
end;
{ TFoo }
procedure TFoo.Foo;
begin
WriteLn('TFoo.Foo');
end;
procedure TFooBar.Bar;
begin
WriteLn('TFooBar.Bar');
end;
procedure TFooBar.Foo;
begin
WriteLn('TFooBar.Foo');
end;
procedure TFooBarToo.Bar;
begin
WriteLn('TFooBarToo.Bar');
end;
procedure TFooBarToo.Foo;
begin
WriteLn('TFooBarToo.Foo');
end;
procedure TVirtFoo.Foo;
begin
WriteLn('TVirtFoo.Foo');
end;
procedure TVirtFooBar.Bar;
begin
WriteLn('TVirtFooBar.Bar');
end;
procedure TVirtFooBar.Foo;
begin
WriteLn('TVirtFooBar.Foo');
end;
var
Intf : IInterface;
IntfFoo : IFoo;
IntfBar : IBar;
begin
try
{=== TFooBar ===}
WriteLn('=== TFooBar ===');
Intf := TFooBar.Create;
Supports(Intf, IFoo, IntfFoo);
IntfFoo.Foo; // TFoo.Foo
Supports(Intf, IBar, IntfBar);
IntfBar.Foo; // TFooBar.Foo
IntfBar.Bar; // TFooBar.Bar
IntfFoo := IntfBar;
IntfFoo.Foo; // TFooBar.Foo
{=== TFooBarToo ===}
WriteLn('=== TFooBarToo ===');
Intf := TFooBarToo.Create;
Supports(Intf, IFoo, IntfFoo);
IntfFoo.Foo; // TFooBarToo.Foo
Supports(Intf, IBar, IntfBar);
IntfBar.Foo; // TFooBar.Foo
IntfBar.Bar; // TFooBar.Bar
IntfFoo := IntfBar;
IntfFoo.Foo; // TFooBar.Foo
{=== TVirtFooBar ===}
WriteLn('=== TVirtFooBar ===');
Intf := TVirtFooBar.Create;
Supports(Intf, IFoo, IntfFoo);
IntfFoo.Foo; // TVirtFooBar.Foo
Supports(Intf, IBar, IntfBar);
IntfBar.Foo; // TVirtFooBar.Foo
IntfBar.Bar; // TVirtFooBar.Bar
IntfFoo := IntfBar;
IntfFoo.Foo; // TVirtFooBar.Foo
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
if DebugHook <> 0 then
ReadLn;
end.
More information about the fpc-devel
mailing list