코딩 이야기/델파이 코딩
델파이 상속(Inheritance) 설명 및 예제
안개소리
2025. 4. 28. 14:33
상속(Inheritance) 설명 및 예제
1. 상속(Inheritance)이란?
상속은 객체 지향 프로그래밍(OOP)의 중요한 개념 중 하나로, 기존에 정의된 클래스(부모 클래스, 상위 클래스, Base Class, Ancestor)의 속성(필드, 속성)과 기능(메소드)을 물려받아 새로운 클래스(자식 클래스, 하위 클래스, Derived Class, Descendant)를 정의하는 것을 말합니다.
델파이에서는 클래스 선언 시 괄호 안에 부모 클래스를 명시하여 상속 관계를 정의합니다. 예를 들어, type TChildClass = class(TParentClass)
와 같이 선언하면 TChildClass
는 TParentClass
로부터 상속받게 됩니다. 델파이의 모든 클래스는 명시적으로 상속받지 않으면 자동으로 최상위 클래스인 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
키워드를 사용하여 부모의 기능을 활용하고, virtual
과 override
를 통해 다형성을 구현하여 유연하고 확장 가능한 코드를 작성할 수 있습니다. 객체를 생성했다면 반드시 Free
를 통해 해제하여 메모리 누수를 방지해야 합니다.