코딩 이야기/델파이 코딩

델파이 상속(Inheritance) 설명 및 예제

안개소리 2025. 4. 28. 14:33

상속(Inheritance) 설명 및 예제

1. 상속(Inheritance)이란?

상속은 객체 지향 프로그래밍(OOP)의 중요한 개념 중 하나로, 기존에 정의된 클래스(부모 클래스, 상위 클래스, Base Class, Ancestor)의 속성(필드, 속성)과 기능(메소드)을 물려받아 새로운 클래스(자식 클래스, 하위 클래스, Derived Class, Descendant)를 정의하는 것을 말합니다.

델파이에서는 클래스 선언 시 괄호 안에 부모 클래스를 명시하여 상속 관계를 정의합니다. 예를 들어, type TChildClass = class(TParentClass)와 같이 선언하면 TChildClassTParentClass로부터 상속받게 됩니다. 델파이의 모든 클래스는 명시적으로 상속받지 않으면 자동으로 최상위 클래스인 TObject를 상속받습니다.

상속의 장점

  • 코드 재사용성: 부모 클래스에 정의된 코드(필드, 메소드 등)를 자식 클래스에서 다시 작성할 필요 없이 그대로 사용할 수 있습니다.
  • 계층 구조 설계: 클래스 간의 'is-a' 관계(예: '개(Dog)는 동물(Animal)이다')를 명확하게 표현하여 프로그램의 구조를 논리적으로 설계할 수 있습니다.
  • 다형성(Polymorphism) 구현 기반: 부모 클래스 타입의 변수가 자식 클래스 객체를 참조할 수 있게 하며, 오버라이딩(Overriding)을 통해 같은 이름의 메소드가 객체 타입에 따라 다르게 동작하도록 구현할 수 있습니다.
  • 유지보수 용이성: 공통 기능은 부모 클래스에서 관리하고, 각 자식 클래스는 자신만의 특화된 기능만 추가하거나 수정하면 되므로 코드 수정 및 관리가 용이해집니다.

주요 키워드 및 개념

  • inherited: 자식 클래스에서 부모 클래스의 메소드(주로 생성자, 소멸자, 오버라이딩된 메소드)를 호출할 때 사용합니다. 부모의 기능을 확장하거나 기본 동작을 수행한 후 추가 작업을 할 때 필수적입니다.
  • virtual: 부모 클래스에서 메소드를 선언할 때 사용하며, 이 메소드가 자식 클래스에서 재정의(오버라이딩)될 수 있음을 나타냅니다.
  • dynamic: virtual과 유사하게 오버라이딩될 수 있음을 나타내지만, 메소드 호출 방식(디스패치 메커니즘)이 다릅니다. 일반적으로 virtual이 더 많이 사용됩니다.
  • override: 자식 클래스에서 부모 클래스의 virtual 또는 dynamic 메소드를 재정의할 때 사용합니다. 부모와 동일한 이름과 파라미터를 가져야 합니다.
  • 접근 지정자 (private, protected, public, published): 상속 시 멤버의 접근 가능 범위를 결정합니다. protected 멤버는 해당 클래스와 자식 클래스에서 접근 가능합니다.

2. 델파이 상속 예제 (TAnimal, TDog)

'동물(Animal)' 클래스를 정의하고, 이를 상속받는 '개(Dog)' 클래스를 만드는 예제입니다. 상속, 메소드 오버라이딩, inherited 키워드 사용법을 보여줍니다.

unit Unit1;

interface

uses
  System.SysUtils, Vcl.Dialogs; // ShowMessage 사용

type
  // 부모 클래스 (Ancestor Class)
  TAnimal = class(TObject)
  private
    FName: string;
  protected // 자식 클래스에서 접근 가능하도록 protected 사용
    function GetKind: string; virtual; // 종류를 반환하는 가상 함수
  public
    constructor Create(const AName: string);
    // 자식 클래스에서 재정의 가능하도록 virtual 선언
    procedure MakeSound; virtual;
    procedure Introduce;
    property Name: string read FName;
    property Kind: string read GetKind; // 읽기 전용 속성
  end;

  // 자식 클래스 (Descendant Class) - TAnimal을 상속받음
  TDog = class(TAnimal)
  private
    FBreed: string; // 개 품종 (자식 클래스에만 있는 필드)
  protected
    function GetKind: string; override; // 부모의 GetKind 재정의
  public
    // 부모 생성자를 확장하는 새로운 생성자
    constructor Create(const AName: string; const ABreed: string);
    // 부모의 MakeSound 메소드를 재정의 (override)
    procedure MakeSound; override;
    // 개 고유의 메소드 추가
    procedure WagTail;
    property Breed: string read FBreed;
  end;

implementation

{ TAnimal }

constructor TAnimal.Create(const AName: string);
begin
  inherited Create; // TObject.Create 호출
  FName := AName;
end;

function TAnimal.GetKind: string;
begin
  Result := '알 수 없는 동물'; // 기본 종류
end;

procedure TAnimal.MakeSound;
begin
  ShowMessage(Name + '이(가) 소리를 냅니다. (...)'); // 기본 소리
end;

procedure TAnimal.Introduce;
begin
  ShowMessage(Format('이름: %s, 종류: %s', [Name, Kind]));
end;

{ TDog }

constructor TDog.Create(const AName: string; const ABreed: string);
begin
  // 부모 클래스의 생성자를 먼저 호출하여 이름(Name) 초기화
  inherited Create(AName);
  // 자식 클래스만의 필드 초기화
  FBreed := ABreed;
end;

function TDog.GetKind: string;
begin
  Result := '개'; // 개 종류 반환
end;

// 부모의 MakeSound를 오버라이딩
procedure TDog.MakeSound;
begin
  // inherited; // 필요하다면 부모의 MakeSound를 호출할 수 있음
  ShowMessage(Name + ' (품종: ' + Breed + ')이(가) 짖습니다: 멍멍!');
end;

// TDog만의 고유 메소드
procedure TDog.WagTail;
begin
  ShowMessage(Name + '이(가) 꼬리를 흔듭니다.');
end;

// === 상속 및 다형성 사용 예제 ===
procedure TForm1.Button1Click(Sender: TObject);
var
  Animal1: TAnimal;
  Dog1: TDog;
  Zoo: array[0..1] of TAnimal; // 부모 클래스 타입 배열 (다형성 활용)
begin
  // 1. 부모 및 자식 클래스 객체 생성
  Animal1 := TAnimal.Create('동물이');
  Dog1 := TDog.Create('뽀삐', '진돗개');

  try
    // 2. 각 객체의 메소드 호출
    Animal1.Introduce; // 이름: 동물이, 종류: 알 수 없는 동물
    Animal1.MakeSound; // 동물이이(가) 소리를 냅니다. (...)

    Dog1.Introduce;    // 이름: 뽀삐, 종류: 개 (오버라이드된 GetKind 호출)
    Dog1.MakeSound;    // 뽀삐 (품종: 진돗개)이(가) 짖습니다: 멍멍! (오버라이드된 MakeSound 호출)
    Dog1.WagTail;      // 뽀삐이(가) 꼬리를 흔듭니다. (TDog 고유 메소드)

    ShowMessage('--- 다형성 테스트 ---');

    // 3. 다형성: 부모 클래스 타입 변수에 자식 객체 할당
    Zoo[0] := TAnimal.Create('야옹이'); // TAnimal 객체
    Zoo[1] := TDog.Create('바둑이', '삽살개'); // TDog 객체지만 TAnimal 타입으로 취급

    // 배열 순회하며 MakeSound 호출
    // Zoo[0]은 TAnimal의 MakeSound 호출
    // Zoo[1]은 TDog의 오버라이드된 MakeSound 호출 (이것이 다형성!)
    Zoo[0].MakeSound;
    Zoo[1].MakeSound;

  finally
    // 4. 생성된 모든 객체 해제 (매우 중요!)
    Animal1.Free;
    Dog1.Free;
    Zoo[0].Free;
    Zoo[1].Free;
  end;
end;

end.

3. 정리

상속은 델파이에서 클래스 간의 관계를 설정하고 코드를 효율적으로 재사용하는 강력한 메커니즘입니다. inherited 키워드를 사용하여 부모의 기능을 활용하고, virtualoverride를 통해 다형성을 구현하여 유연하고 확장 가능한 코드를 작성할 수 있습니다. 객체를 생성했다면 반드시 Free를 통해 해제하여 메모리 누수를 방지해야 합니다.