Articles Class Implementing Two Interfaces with Duplicate Method Names by Jim McKeeth

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,439
Credits
574
Class Implementing Two Interfaces with Duplicate Method Names
[SHOWTOGROUPS=4,20]
Jim McKeeth
26/11/2019

Delphi only supports Для просмотра ссылки Войди или Зарегистрируйся. A Delphi class can only descend from a single parent class, but a Delphi class can Для просмотра ссылки Войди или Зарегистрируйся.

Код:
type
TAthlete = class(THuman, IWalker, IJumper)

The TAthlete descends from the THuman parent class (which presumably descends from Для просмотра ссылки Войди или Зарегистрируйся) and it implements both the IWalker and IJumper interfaces. What if both IWalker and IJumper contain a run method.
Код:
type
THuman = class(TInterfacedObject)
procedure walk; virtual;
end;

IJumper = Interface(IInterface)
procedure run;
end;

IWalker = Interface(IInterface)
procedure run;
end;

TAthlete = class(THuman, IWalker, IJumper)
end;


Data Model

Right now TAthlete doesn't implement the members of IWalker or IJumper.
  • [dcc32 Error] E2291 Missing implementation of interface method IJumper.run
  • [dcc32 Error] E2291 Missing implementation of interface method IWalker.run
When we implement these interfaces in TAthlete, what if we want to have a different run method for IWalker vs IJumper? Enter the Для просмотра ссылки Войди или Зарегистрируйся.
Interface Method Resolution Clause
When a class implements two or more interfaces that have identically named methods, use method resolution clauses to resolve the naming conflicts. You can override the default name-based mappings by including method resolution clauses in a class declaration. We might implement those interfaces like this:
Код:
type
TAthlete = class(THuman, IWalker, IJumper)
public
procedure IWalker.run = PowerWalk;
procedure IJumper.run = RealRun;
private
procedure PowerWalk;
procedure RealRun;
end;

5226.method_5F00_resolution.png

But what happens if I call Run on a class reference to an TAthlete object? It doesn't exist. There is no Run method on TAthlete, and both PowerWalk and RealRun are private, so they aren't accessible via a class reference either.

Код:
  var Athlete := TAthlete.Create;
try
(* These give E2003 Undeclared identifier
Athlete.run; // There is no Run method on TAthlete
Athlete.PowerWalk; // PowerWalk is Private
Athlete.RealRun; // Also private *)

// To access Run we must have an Interface reference
IWalker(Athlete).Run; // Calls TAthlete's RealRun method
IJumper(Athlete).Run; // Calls TAthlete's PowerWalk method
finally
Athlete.Free;
end;


If we wanted to call Run on TAthlete we could do that with a little change.
Код:
type
TAthlete = class(THuman, IWalker, IJumper)
public
procedure IWalker.Run = PowerWalk;
procedure Run;
private
procedure PowerWalk;
end;

8561.less_2D00_explicit.png

Now IJumper uses the default name-based mapping, which IWalker uses the manually mapped method
Код:
  var Athlete := TAthlete.Create;
try
Athlete.Run; // We now have a Run method
IWalker(Athlete).Run; // Calls TAthlete's PowerWalk method (not a real run)
IJumper(Athlete).Run; // Calls the real Run method on TAthlete
finally
Athlete.Free;
end;

It seems like it would usually be a good idea to be explicit in all the methods implemented by interfaces when you have a conflict like this, but there could be a reason to be less explicit in certain use cases. It is great that Delphi gives you the flexibility to implement this either way necessary.

[/SHOWTOGROUPS]
 
Последнее редактирование: