Delphi only supports single inheritance. A Delphi class can only descend from a single parent class, but a Delphi class can implement multiple interfaces.
|
<span style="color:#000084;font-weight:bold;">type</span> TAthlete = <span style="color:#000084;font-weight:bold;">class</span>(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.
|
<span style="color:#000084;font-weight:bold;">type</span> THuman = <span style="color:#000084;font-weight:bold;">class</span>(TInterfacedObject) <span style="color:#000084;font-weight:bold;">procedure</span> walk; <span style="color:#000084;font-weight:bold;">virtual</span>; <span style="color:#000084;font-weight:bold;">end</span>; IJumper <span style="color:#000084;font-weight:bold;">= Interface</span>(IInterface) <span style="color:#000084;font-weight:bold;">procedure</span> run; <span style="color:#000084;font-weight:bold;">end</span>; IWalker <span style="color:#000084;font-weight:bold;">= Interface</span>(IInterface) <span style="color:#000084;font-weight:bold;">procedure</span> run; <span style="color:#000084;font-weight:bold;">end</span>; TAthlete = <span style="color:#000084;font-weight:bold;">class</span>(THuman, IWalker, IJumper) <span style="color:#000084;font-weight:bold;">end</span>; |

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:
|
<span style="color:#000084;font-weight:bold;">type</span> TAthlete = <span style="color:#000084;font-weight:bold;">class</span>(THuman, IWalker, IJumper) <span style="color:#000084;font-weight:bold;">public</span> <span style="color:#000084;font-weight:bold;">procedure</span> IWalker.run = PowerWalk; <span style="color:#000084;font-weight:bold;">procedure</span> IJumper.run = RealRun; <span style="color:#000084;font-weight:bold;">private</span> <span style="color:#000084;font-weight:bold;">procedure</span> PowerWalk; <span style="color:#000084;font-weight:bold;">procedure</span> RealRun; <span style="color:#000084;font-weight:bold;">end</span>;<br><img alt=" " height="424" src="https://blogs.embarcadero.com/wp-content/uploads/2020/08/5226.method_5F00_resolution.png" width="549" style="cursor: zoom-in;"> |
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.
|
<span style="color:#000084;font-weight:bold;">var</span> Athlete := TAthlete.Create; <span style="color:#000084;font-weight:bold;">try</span> <span style="color:#808080;">(* These give E2003 Undeclared identifier</span> <span style="color:#808080;"> Athlete.run; // There is no Run method on TAthlete</span> <span style="color:#808080;"> Athlete.PowerWalk; // PowerWalk is Private</span> <span style="color:#808080;"> Athlete.RealRun; // Also private *)</span> <span style="color:#808080;">// To access Run we must have an Interface reference</span> IWalker(Athlete).Run; <span style="color:#808080;">// Calls TAthlete's RealRun method</span> IJumper(Athlete).Run; <span style="color:#808080;">// Calls TAthlete's PowerWalk method</span> <span style="color:#000084;font-weight:bold;">finally</span> Athlete.Free; <span style="color:#000084;font-weight:bold;">end</span>;<br><br> |
If we wanted to call Run on TAthlete we could do that with a little change.
|
<span style="color:#000084;font-weight:bold;">type</span> TAthlete = <span style="color:#000084;font-weight:bold;">class</span>(THuman, IWalker, IJumper) <span style="color:#000084;font-weight:bold;">public</span> <span style="color:#000084;font-weight:bold;">procedure</span> IWalker.Run = PowerWalk; <span style="color:#000084;font-weight:bold;">procedure</span> Run; <span style="color:#000084;font-weight:bold;">private</span> <span style="color:#000084;font-weight:bold;">procedure</span> PowerWalk; <span style="color:#000084;font-weight:bold;">end</span>; |

Now IJumper uses the default name-based mapping, which IWalker uses the manually mapped method
|
<span style="color:#000084;font-weight:bold;">var</span> Athlete := TAthlete.Create; <span style="color:#000084;font-weight:bold;">try</span> Athlete.Run; <span style="color:#808080;">// We now have a Run method</span> IWalker(Athlete).Run; <span style="color:#808080;">// Calls TAthlete's PowerWalk method (not a real run)</span> IJumper(Athlete).Run; <span style="color:#808080;">// Calls the real Run method on TAthlete</span> <span style="color:#000084;font-weight:bold;">finally</span> Athlete.Free; <span style="color:#000084;font-weight:bold;">end</span>; |
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.