[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