Delphi Class에서 Interface 두 개 구현할 때, 이 둘이 동일한 이름의 메소드(Method)를 가지고 있다면?
2019.12.11 15:01
Jim McKeeth의 블로그에서 흥미로운 주제가 있어서 번역하였습니다. 본문에는 해당 요소들에 대한 링크가 있어서 더 깊이있게 이해할 수 있습니다. 본문 링크: https://community.idera.com/developer-tools/b/blog/posts/class-implementing-two-interfaces-with-duplicate-method-names
델파이는 ‘단일 상속’ 만을 지원합니다. 즉, 부모 클래스는 오직 1개만 가질 수 있습니다. 하지만, 인터페이스는 여러개 구현할 수 있습니다.
type TAthlete = class(THuman, IWalker, IJumper)
TAthlete의 부모 클래스는 (아마 TInterfacedObject의 후손인) THuman입니다. 그리고 IWalker와 IJumper 인터페이스를 구현합니다. 만약 IWalker와 IJumper 모두 run이라는 메소드를 가지고 있다면 어떻게 할까요?
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;
IWalker와 IJumper의 멤버들을 TAthlete에서 아직은 구현하지 않은 상태입니다.
- [dcc32 Error] E2291 Missing implementation of interface method IJumper.run
- [dcc32 Error] E2291 Missing implementation of interface method IWalker.run
TAthlete에서 이 인터페이스들을 구현할 때 IWalker와 IJumper 별로 다르게 run 메소드를 구현하고 싶다면? Method Resolution Clause (메소드 해소 구문)를 살펴보세요.
인터페이스 메소드 해소 구문
어느 클래스에서 2개 이상의 인터페이스를 구현하는데, 이 인터페이스들이 같은 이름으로된 메소드를 가지고 있다면 메소드 해소 구문을 사용하여 이름 충돌을 해소합니다. 클래스 선언부에 메소드 해소 구문을 넣어서 디펄트 이름-기반 매핑을 오버라이드할 수 있습니다. 아마 아래와 같이 인터페이스들을 구현하게 됩니다.
type TAthlete = class(THuman, IWalker, IJumper) public procedure IWalker.run = PowerWalk; procedure IJumper.run = RealRun; private procedure PowerWalk; procedure RealRun; end;
하지만, 만약 TAthlete 개체에서 Run을 호출하면 어떻게 될까요? TAthlete 클래스에는 Run 메소드가 없습니다. 그리고 PowerWalk와 RealRun은 모두 private 멤버라서 클래스 참조로는 접근할 수 없습니다.
var Athlete := TAthlete.Create; try (* E2003 식별자가 선언되지 않았다는 오류 발생 Athlete.run; // TAthlete에는 Run 메소드가 현재 없음 Athlete.PowerWalk; // PowerWalk는 Private 멤버임 Athlete.RealRun; // 이것 또한 Private 멤버임 *) // Run을 접근하려면 인터페이스 레퍼런스가 있어야 함 IWalker(Athlete).Run; // TAthlete의 RealRun 메소드 호출하기 IJumper(Athlete).Run; // TAthlete의 PowerWalk 메소드 호출하기 finally Athlete.Free; end;
TAthlete에서 Run을 호출하려면 약간 변경을 해야 합니다.
type TAthlete = class(THuman, IWalker, IJumper) public procedure IWalker.Run = PowerWalk; procedure Run; private procedure PowerWalk; end;
이제 IJumper는 디펄트 이름 기반 맵핑을 사용하고, IWalker는 코드로 변경한 메소드를 사용하게 되었습니다.
var Athlete := TAthlete.Create; try Athlete.Run; // 이제 Run 메소드를 사용할 수 있음 IWalker(Athlete).Run; // TAthlete의 PowerWalk 메소드 호출 IJumper(Athlete).Run; // TAthlete의 진짜 Run 메소드 호출 finally Athlete.Free; end;
이름이 충돌할 경우에는 인터페이스를 명시하는 것이 일반적으로 좋은 방식입니다. 하지만, 경우에 따라 이와 같이 명시하지 않고 사용할 필요가 있는 경우도 있습니다. 델파이는 이 두 방식 모두를 제공하므로 개발자가 유연하게 코드를 작성할 수 있습니다
<Jim McKeeth의 블로그에서 흥미로운 주제가 있어서 번역
본문에는 해당 요소들에 대한 링크가 있어서 더 깊이있게