type TAthlete = class(THuman, IWalker, IJumper)
The TAthlete descends from the THuman parent class (which presumably descends from TInterfacedObject) 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; virtualend= Interface(IInterface) procedure run; end= Interface(IInterface) procedure run; endclass(THuman, IWalker, IJumper) end
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 Method Resolution Clause.
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
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
Now IJumper uses the default name-based mapping, which IWalker uses the manually mapped methodvar 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.