메서드 재정의
클래스 상속에서 주목할 만한 것은, 단순한 기능 상속이 아닙니다. 클래스 상속의 추상적인 기능을 구체적인 처리로 전환하는 것은 기능의 재정에 있다고 생각됩니다. 이 기능은 슈퍼 클래스의 메소드를 무시하고 서브 클래스의 메서드를 먼저 호출하게 하는 메서드 재정의라는 기능을 제공합니다. 이것을 일반적으로 재정의라고 합니다. (Overriding)
메서드 재정의는 슈퍼 클래스의 메소드와 같은 이름, 같은 반환 형식, 같은 인수의 메소드를 서브 클래스에서 정의할 수 있도록 합니다. 일반적으로 이러한 메서드 이름과 메서드의 반환 값과 인수 형식 전체를 서명이라고 합니다.(Signiture) 메서드 재정의는 서명이 같은 메서드를 하위 클래스에서 새롭게 정의하고 구현하는 것입니다.
#import <stdio.h>
#import <objc/Object.h>
@interface SuperClass : Object
- (void) method;
@end
@interface SubClass : SuperClass
(void) method;
@end
@implementation SuperClass
- (void) method
{
printf ( "SuperClass.method \ n");
}
@end
@implementation SubClass
- (void) method
{
printf ( "SubClass.method \ n");
}
@end
int main()
{
[SuperClass alloc] method] ;
[SubClass alloc] method];
return 0;
}
이 프로그램은 슈퍼 클래스인 SuperClass 클래스와 서브 클래스의 SubClass 클래스에서 서명이 동일한 method 메서드를 재선언 및 재정의하고 있습니다. Objective-C는 이러한 메서드의 충돌은 컴파일 오류가 아닌 메서드 재정의로 인식하게 됩니다.
재정의된 메서드의 효과는 main() 메소드의 실행 결과를 보면 확인할 수 있습니다. 인스턴스가 SuperClass인 경우 SuperClass 클래스의 method 메서드를 호출하고, 인스턴스가 SubClass 클래스의 인스턴스면 SubClass의 method 메서드가 호출됩니다. 이것은 SubClass가 SuperClass의 method 메서드를 무시하고 새롭게 자신이 정의한 자신만의 method 메서드를 재정의하고 호출했음을 나타냅니다.
재정의 결과로 프로그램은 다양성을 제공합니다. 메서드를 호출하는 코드는 코드를 변경하지 않고서도 인스턴스에서 호출하는 적절한 방법을 선택 할 수 있게 될 것입니다. 다음과 같은 코드를 가정해보십시오.
void CallMethod(id obj)
{
[obj method];
}
int main()
{
CallMethod([SuperClass alloc]);
CallMethod([SubClass alloc]);
return 0;
}
이 코드는 CallMethod() 함수에서 id 형식의 객체를 인수로 받고 있습니다. 이 함수는 받은 객체의 method 메서드를 호출합니다.
그러나, 결과적으로 이 함수가 어떤 메서드를 호출하는 것은 전달되는 객체의 인스턴스에 따라 다르게 됩니다. 함수가 호출하는 실제 메서드는 런타임 때에 결정이 됩니다. C언어에서는 이와 같은 기능을 구현하기 위해서는 switch 문으로 분기해서 함수를 호출하게 하거나 런타임에서 동적으로 함수 포인터와 같은것을 이용해서 호출해야만 가능합니다. Objective-C에서는 그런 부가적인 행동 없이 동적으로 호출되는 방법을 언어 수준에서 지원하고 있는 것입니다.
그런데, 슈퍼 클래스의 메소드가 완전히 무시되어버리면 곤란할 경우도 있습니다. 특히, 메소드 재정의의 목적이 기능 확장이라면 확장된 부분을 서브 클래스에서 작성하고 나머지 기본적인 처리 부분은 슈퍼 클래스에 정의된 메서드에 맡겨서 처리해야 합니다. 이것을 구현하기 위해서는 하위 클래스의 재정의 메서드에서 수퍼 클래스의 정의된 메서드를 호출해야 합니다.
슈퍼 클래스의 메소드를 서브 클래스에서 명시적으로 호출하려면 super를 이용합니다. super는 슈퍼 클래스를 보유하는 인스턴스 메서드의 메시지 식에서만 사용할 수있는 특별한 이름으로, 슈퍼 클래스의 메소드를 명시적으로 호출합니다. self는 인스턴스 메서드에 존재하는 암묵적인 id 변수 였지만, super 는 변수가 아님을 주의 하십시오.
#import <stdio.h>
#import <objc/Object.h>
@interface SuperClass : Object
{
int x;
}
- (void) method;
@end
@interface SubClass : SuperClass
- (void) method;
@end
@implementation SuperClass
- (void) method
{
printf ( "SuperClass.method \n");
}
@end
@implementation SubClass
- (void) method
{
printf ( "SubClass.method %d \n", x);
[super method];
}
@end
int main()
{
[SubClass alloc] method];
return 0;
}