OVERRIDING INTERFACE METHODS IN SUBCLASSES
// 상속클래스에서 재정의 되는 인터페이스 메서드
내용에 앞서:
언급된 관련 서적 :
1. Don Box's Essential .NET Volume 1
번역 :
1.Polymorphism : 다형성, 다형적
2.Mathod signature : 메서드 서명, 메서드 식별자
(이를테며 void a(int i), void a(int i, float f) 오버로딩 함수라면 반환타입, 인자갯수, 인자 타입등..)
3.SubClass : 상속된 클래스
4.Override : 재정의
5.Implementation : 인터페이스의 최종 구현부 //(Java의 final)
내용 :
C#(일반적으로 닷넷)은 상속된 클래스 내부의 메소드들의 재정의을 위한 virtual/abstract와 계층적 구조를
이용한 다형성을 제공합니다.
얼핏 보기에, C#은 그 개념에 있어서 C++과 Java 둘다의 특징을 보이지만, 그것은 피상에 불과합니다.
C#에서 인터페이스를 정의는 다음과 같습니다.
public interface IFoo {
void doSomething();
}
코드참고1.
클래스A를 정의하여 인터페이스로 구현을 하게 됩니다.
public class A : IFoo {
public void doSomething() {
Console.WriteLine("In A.doSomething()");
}
}
코드참고2.
A를 IFoo 인터페이스로써 사용할 수 있습니다.
IFoo foo = new A();
foo.doSomething(); //outputs: In A.doSomething()
코드참고3.
기본적인 예로써, 이것이 가능한 것은 닷넷 런타임이 IFoo.doSomething()을 참조하는 곳에 A.doSomething()
을 찾아내며 오브젝트 참조의 메모리 출력되는 주소 공간을 조작하여 이루어 집니다.
이것은 언어에 따라 다르지만, 일반적으로 (간단하게) 개체에서 지원하는 각 유형의 구현에 매핑 개체에서 사용할 각 방법에 대한 주소 위치의 목록을 하나 이상 vtables를 사용하는것을 포함합니다.
가상 메서드들이 vtable로 컴파일 되는 시점에, 일반적인 메서드들은 자신들의 주소들을 가지는 코드안으로 컴파일이 되며,
이 포인터는 런타임 시점에서 언어가 가지는 다형성 규칙과 특정 참조에 따라 실제 메서드의 위치로 변환됩니다.
일단 virtual로
표기
되면, 함수의
메서드 서명은 타입 계층을
통한 virtual가 유지됩니다.
virtual로 표기 되면 메소드 서명에 대한 호출은 항상 어디 유형 계층 구조에 있는 참조 점에 관계없이 조회 vtable list을 통해 이동 합니다.
인터페이스도 타입이므로, 정의된 인터페이스 메서드는 가상이기 때문에 이로써, 정의된 인터페이스 메서드는
재 정의가 될 수가 있습니다.
C#에서(C++동일, Java제외) 정의된 가상 메서드들은 일반적으로 그들의 서명으로 표기되는 'virtual'키워드가 요구 됩니다.
(그래서 컴파일러는 메서드의 실제 주소값 대신 추가된 vtable 진입점을 알고 있게 됩니다.)
구현을 위해 인터페이스 메서드 서명을 상속하는 클래스들이 확실하게 요구하는 동안 인터페이스들의 요청은 잠시
보류가 됩니다.
(엄밀히 말해서 인터페이스들은 구현되는 클래스들의 기본 타입은 아니며, 이에 대한 자세한 정보는
Don Box's Essential .NET Volume 1 책의 70페이지를 활용바랍니다.)
또한 C#(C++동일,Java제외)에서 또다른 키워드 'override'는 메서드 서명의 vtable진입점으로 변환되기 위해 하위 클래스에서 요청을 하게 됩니다.
결과적으로, C#의 'sealed' 키워드(Java의 'final'과 동일)는 비-가상 메서드를 만들수 없게 만들지는 못해도,
하위 클래스에서 'sealed' 키워드가 선언된 인터페이스를 재 정의를 못하게 할 수는 있습니다.
virtual 메서드 서명들은 상속 클래스에 vitual로 남게 되고, 인터페이스 메서드들이 virtual가 되면 인터페이스 메서드로써
상속 클래스들의 클래스들에서 구현 부 인터페이스들로써의 재정의가 가능하게 됩니다.
이하 코드는 이상 내용의 참고:
public class A : IFoo {
public void doSomething() {
Console.WriteLine("In A.doSomething()");
}
}
코드참고4.
public class B : A {
public override void doSomething() {
Console.WriteLine("In B.doSomething()");
}
}
코드참고5.
C#에서 동작하지 않고 다음 에러문구를 출력합니다:
B.doSomething()' : cannot override inherited member 'A.doSomething()'
because it is not marked virtual, abstract, or override
//B.doSomething() : A.doSomething()를 구성요소로써 재정의 할 수 없습니다.
A.doSomething()에 virtual, abstract 또는 override 표시가 없기 때문입니다.//
A를 간단히 해서 'override' 를 메서드 정의에서 제외 시키면 다음과 같이 출력됩니다.
public class B : A {
public void doSomething() {
Console.WriteLine("In B.doSomething()");
}
}
코드참고6.
컴파일 되지만 원하는 결과가 또한 아니며 다음의 경고 메세지를 알려주게 됩니다.:
The keyword new is required on 'B.doSomething()' because it hides inherited member 'A.doSomething()'
new 키워드가 'B.doSomething()'에 필요합니다. 상속 상위 개체 함수'A.doSomething()'에 의해 숨겨졌습니다.
"상속 상위 개체 맴버에의해 숨겨지다" 라는 의미를 해석해 보자면
C#(C++동일,Java제외)은 저러한 기반 클래스들의 동일한 서명을 가진 상속클래스들의 메소드들을 허용합니다.
여기서 다시 상기 해보자면 virtual 키워드로 구현된 것이 아니라면 'vtable'목록에 포함되지 않습니다.
쉽게 말하자면 B는 두 개의 doSomething()메서드를 가지게 됩니다.
결과 인식 메서드는A로부터 상속 받은 것, 그리고 B에서 새로 정의한 것 2개가 되며, 그런 이유로 new 키워드가
새로 필요하다는 경고 메세지를 출력하게 됩니다.
또한 다음에서 보듯, IFoo로써 B를 사용하는 것은 의도하는 바가 아닙니다.
IFoo foo = new B();
foo.doSomething(); //outputs: In A.doSomething() // 원하는 결과가 아님.
한가지 해결점은 'virtual' 메서드를 A.doSomething()앞에 표시하는 것이지만 만약 A 코드에 접근할 수 없는 상황이라면
어떻게 해야할까요?
C#상에서 모든 것을 충족시키는 IFoo의 구현부인 B로써는 다음과 같습니다:
public class B : A, IFoo {
void IFoo.doSomething() {
Console.WriteLine("In B.doSomething()");
}
}
IFoo foo = new B();
foo.doSomething(); //outputs: In B.doSomething()
코드참고7.
그러나 위 사항은 저장 영역으로 B는 다른 syntax임을 주목 해야 합니다.
'public' 키워드를 제외시킴으로써 IFoo.doSomething의 구현을 명확하게 할 수가 있습니다.
이전과 같은 경고와 에러가 뜨지 않게 하려면, A에서 했던 것과 같은 단순화된 메소드를 구현할 수는 없습니다.
이것은 외부 구현부에서 변경하여, 이 클래스 선언을 통해 B를 private 하게 하고 public 키워드를 삭제할 필요가 있습니다.
B에서 구현된 doSomething()은 인스턴스화 된 B에서는 접근 안되며, IFoo에서만 가능합니다.
B b=newB();
A a =b;
b.doSomething(); //outputs: In A.doSomething() !!
a.doSomething(); // 역시나 위와 동일한 결과
Essential .NET Volume 1 page 169:
...인터페이스 메서드의 구현부 에서 선언은 'final'이며, 'sealed'나 'override' 또한 제공됩니다.
C#(.NET)은 뚜렷한 base class designer(기반 클래스 디자이너)의 디자인 결정을 해야 하는 일종에 디자인 철학을
'Programming > Design' 카테고리의 다른 글
OCP : The Open-Closed Principle (0) | 2011.08.05 |
---|---|
SRP : The Single Responsibility Principle (0) | 2011.07.18 |