프로퍼티 오버라이드와 재선언
프로퍼티 오버라이드와 재선언
프로퍼티는 하위 클래스에서 오버라이드(override)될 수도 있고 재선언(redeclare)될 수도 있어요.
본문
프로퍼티 타입이 선언되면 프로퍼티 재선언(redeclaration)으로 동작하고, 그렇지 않으면 프로퍼티 오버라이드(override)예요. 유일한 차이는 이래요. 오버라이드는 상속받은 수식어를 새 수식어로 대체하거나 확장하지만, 재선언은 재선언에 존재하지 않는 상속받은 모든 수식어를 숨겨요. 재선언된 프로퍼티의 타입은 부모 클래스 프로퍼티 타입과 같을 필요는 없어요.
아래 예시가 오버라이드와 재선언의 차이를 보여줘요.
type
TAncestor = class
private
FP1 : Integer;
public
property P: integer Read FP1 write FP1;
end;
TP1 = class(TAncestor)
public
// property override
property P default 1;
end;
TPReadOnly = class(TAncestor)
public
// property redeclaration
property P: integer Read FP1;
end;
TP1은 프로퍼티 P를 기본값으로 확장하고, TPReadOnly는 프로퍼티 P를 읽기 전용으로 재선언해요.
Remark TP1은 생성자에서 P의 기본값을 1로 설정해야 해요.
프로퍼티 재선언과 오버라이드 모두에서 getter와 setter에 대한 접근은 항상 정적(static)이에요. 즉 프로퍼티 오버라이드는 객체의 RTTI에만 작용하지, 메서드 오버라이드와 혼동하면 안 돼요.
inherited 키워드는 프로퍼티의 부모 정의를 참조하는 데 쓸 수 있어요. 예를 들어 다음 코드를 볼게요.
type
TAncestor = class
private
FP1 : Integer;
public
property P: integer Read FP1 write FP1;
end;
TClassA = class(TAncestor)
private
procedure SetP(const AValue: char);
function getP : Char;
public
constructor Create;
property P: char Read GetP write SetP;
end;
procedure TClassA.SetP(const AValue: char);
begin
Inherited P:=Ord(AValue);
end;
procedure TClassA.GetP : char;
begin
Result:=Char((Inherited P) and $FF);
end;
TClassA는 P를 정수 프로퍼티 대신 문자 프로퍼티로 재정의하되, 값을 저장하려고 부모의 P 프로퍼티를 사용해요.
프로퍼티에 가상 get/set 루틴을 쓸 때는 주의해야 해요. 상속받은 프로퍼티를 설정하는 것도 여전히 메서드의 일반 상속 규칙을 따른다. 다음 예시를 볼게요.
type
TAncestor = class
private
procedure SetP1(const AValue: integer); virtual;
public
property P: integer write SetP1;
end;
TClassA = class(TAncestor)
private
procedure SetP1(const AValue: integer); override;
procedure SetP2(const AValue: char);
public
constructor Create;
property P: char write SetP2;
end;
constructor TClassA.Create;
begin
inherited P:=3;
end;
이 경우 상속받은 프로퍼티 P를 설정할 때 SetP1 메서드가 오버라이드됐으므로 TClassA.SetP1 구현이 호출돼요.
부모 클래스의 SetP1 구현을 호출해야 한다면 명시적으로 호출해야 해요.
constructor TClassA.Create;
begin
inherited SetP1(3);
end;
재선언된 조상 프로퍼티는 조상으로의 직접 캐스트(direct cast)로 하위 객체 안팎에서 접근할 수 있어요.
function GetP(const AClassA: TClassA): Integer;
begin
Result := TAncestor(AClassA).P;
end;
더 알아보기
- 프로퍼티 정의(Definition)
- 저장 정보(Storage information)