본문 바로가기

Program/Delphi

[Delphi] class 상속, interface 위임

Delphi에서는 기본적으로 다중 상속을 지원하지 않는다. 다중 상속의 위험성은 너무나도 뻔하기에... 뻔하면서도 중요한 부분이기 때문에 많은 사람들이 그렇게 자세히 설명을 하고 있는 것이다.

이는 객체지향을 지향하는 프로그램에서는 공통된 사항이다. 때문에 C#, JAVA도 다중 상속을 허락하지 않는다.  대신 인터페이스를 이용하여 다중 상속(더 분명하게 표현하자면 기능의 위임이라고 하는 것이 좋을 수도 있다)을 지원하고 있다.


그렇다면 다중 상속은 아예 필요하지 않는 것일까? 사람마다 다르겠지만... 난 필요하다고 본다. 다중 상속이 안된다면 논리적으로 불편한 일이 생길 것이다. 실제로 다중 상속을 피해 프로그램을 개발하려고 하다 보면 논리적 구조가 괜히 복잡해지는 경우가 생긴다... 

그리고 필요가 없었다면 다중 상속을 지양하는 C#, JAVA, Delphi 등등의 프로그램 언어에서 인터페이스를 만들지 않았을 것이다. 

다만... 다중 상속의 잠재된 본질적 위험성 때문에 애초에 그 위험의 근원이 될 수 있는 것을 막고 대신에 인터페이스를 이용하려고 한 것이라고 생각된다.


아직 프로그램 개발의 경력이 짧은 나로서는 이 정도 이해하는 것이 다이지만... 아마 다중 상속이 가능한 C++과 같은 프로그램 언어 개발자가 다중 상속이 안되는 다른 객체지향 언어를 이용하여 개발을 한다고 하면 한편으로는 답답한 마음이 생길 수도 있겠다 싶지만...


만약 다중 상속이 가능했다 하더라도 나라면 그냥 상속은 그냥 단일 상속으로만 사용하고, 필요하다면 인터페이스를 사용했을 것 같다. (프로그램에게 무슨 일이 벌어질지 모르기 때문에... 프로그램의 일부 기능이 문제가 생기는 것과 잘못된 상속으로 인하여 프로그램에 전반적으로 문제가 생기는 것의 차이는 비교할 수가 없다...)


원래 이런 말을 쓰려고 한 것이 아닌데... 글을 나눠서 다시 정리해야 하나...?



일단 델파이 Class, Interface는 다음과 같이...


부모 - uParent.pas

unit uParent;


interface


type

  NTestParent1 = class(TObject)

  public

    procedure NTestParent1_Procedure1; virtual; abstract;

  end;


  NTestParent2 = interface

    procedure NTestParent2_Procedure1;

  end;


  NTestParent3 = interface

    procedure NTestParent3_Procedure1;

  end;


implementation


{ NTestParent1 }


end.


자식1 - uChild1.pas (클래스 상속)

unit uChild1;


interface


uses Vcl.Dialogs, uParent;


type

  NTestChild1 = class(NTestParent1)

  public

    procedure NTestParent1_Procedure1; override;

  end;


  NTestChild2 = class(NTestParent1)

  public

    procedure NTestParent1_Procedure1; virtual; abstract;

  end;


implementation


{ NTextChild1 }


procedure NTestChild1.NTestParent1_Procedure1;

begin

  inherited;


  ShowMessage('NTestChild1 - procedure NTestParent1_Procedure1');

end;


end.


자식2 - uChild2.pas (인터페이스 상속)

unit uChild2;


interface


uses Vcl.Dialogs, uParent;


type

  NTestChild2_Interface = interface

    procedure NTestChildInterface_Procedure1;

  end;


  NTestChild2_1 = class(TInterfacedObject, NTestParent2)

  public

    procedure NTestParent2_Procedure1; virtual; abstract;

  end;


  NTestChild2_2 = class(TInterfacedObject, NTestParent2)

  public

    procedure NTestParent2_Procedure1;

  end;


  NTestChild2_3 = class(TInterfacedObject, NTestParent2, NTestParent3)

  public

    procedure NTestParent2_Procedure1;

    procedure NTestParent3_Procedure1;

  end;


implementation


{ NTestChild2_2 }


procedure NTestChild2_2.NTestParent2_Procedure1;

begin

  ShowMessage('nTestChild2_2 - procedure NTestParent2_Procedure1');

end;


{ NTestChild2_3 }


procedure NTestChild2_3.NTestParent2_Procedure1;

begin

  ShowMessage('nTestChild2_2 - procedure NTestParent2_Procedure1');

end;


procedure NTestChild2_3.NTestParent3_Procedure1;

begin

  ShowMessage('nTestChild2_3 - procedure NTestParent3_Procedure1');

end;


end.


자식2의 자식. 즉 손자;; - uChild2_Sub.pas (인터페이스를 이용하여 다중 상속을 지원)

unit uChild2_Sub;


interface


uses Vcl.Dialogs, uChild2;


type

  NTestChild2_Sub1 = class(NTestChild2_1, NTestChild2_Interface)

  public

    procedure NTestParent2_Procedure1; override;

    procedure NTestChildInterface_Procedure1;

  end;


implementation


{ NTestChild2_Sub }


procedure NTestChild2_Sub1.nTestChildInterface_Procedure1;

begin

  ShowMessage('NTestChildInterface -  procedure NTestChildInterface_Procedure1');

end;


procedure NTestChild2_Sub1.NTestParent2_Procedure1;

begin

  ShowMessage('NTestChild2_Sub -  procedure NTestParent2_Procedure1');

end;


end.