2013-05-23 1 views
11

: http://herbsutter.com/2013/05/22/gotw-5-solution-overriding-virtual-functions/ 나는이 매우 이상한 행동을 가로 질러 왔을 때 :오버로딩 기본 방법은이 게시물에서 C++ 동작을 일치 ​​그래서 만약 내가보고 C#을 놀고 있었는데

public class BaseClass 
{ 
    public virtual void Foo(int i) 
    { 
     Console.WriteLine("Called Foo(int): " + i); 
    } 

    public void Foo(string i) 
    { 
     Console.WriteLine("Called Foo(string): " + i); 
    } 
} 

public class DerivedClass : BaseClass 
{ 
    public void Foo(double i) 
    { 
     Console.WriteLine("Called Foo(double): " + i); 
    } 
} 

public class OverriddenDerivedClass : BaseClass 
{ 
    public override void Foo(int i) 
    { 
     base.Foo(i); 
    } 

    public void Foo(double i) 
    { 
     Console.WriteLine("Called Foo(double): " + i); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     DerivedClass derived = new DerivedClass(); 
     OverriddenDerivedClass overridedDerived = new OverriddenDerivedClass(); 

     int i = 1; 
     double d = 2.0; 
     string s = "hi"; 

     derived.Foo(i); 
     derived.Foo(d); 
     derived.Foo(s); 

     overridedDerived.Foo(i); 
     overridedDerived.Foo(d); 
     overridedDerived.Foo(s); 
    } 
} 

출력

Called Foo(double): 1 
Called Foo(double): 2 
Called Foo(string): hi 
Called Foo(double): 1 
Called Foo(double): 2 
Called Foo(string): hi 

분명히 기본 클래스에서보다 구체적인 Foo (int)보다 암시 적으로 변환 된 int가 두 배가되는 것을 선호합니다. 또는 기본 클래스에서 Foo (int)를 숨 깁니까? 하지만 그렇다면 Foo (문자열)가 왜 숨겨져 있지 않습니까? 매우 일관성이 없다고 느낀다 ... Foo (int)를 오버라이드해도 상관 없다. 결과는 같습니다. 아무도 여기서 무슨 일이 일어날 지 설명 할 수 있습니까?

는 (- Liskov 모든 - 그래, 난 그것이 파생 클래스의 기본 방법에 과부하가 나쁜 관행 것을 알고 있지만 나는 아직도! OverriddenDerivedClass에서 푸 (INT)가 호출되지 않습니다 것을 기대하지 않을 것이다)

+4

그것은 거기, – ose

+3

을 아래로 스크롤합니다. "예 나는 그것이 파생 클래스의 기본 방법에 과부하가 나쁜 관행 것을 알고 - Liskov 모두"허, 무엇을 할 때? 기본 방법을 재정의 할 수 있습니까? 어쨌든 +1은 대답을 호기심으로 생각할 것입니다. – bas

+0

분명히 두 번째 일괄 처리에서'overrideDerived'의 메소드를 호출 할 생각 이었습니까? – Rotem

답변

8

그것이 OverriddenDerivedClass 예를 들어 어떻게 작동하는지 설명하기 :

여기에 멤버 조회를위한 C#을 사양에서보세요 : http://msdn.microsoft.com/en-us/library/aa691331%28VS.71%29.aspx 조회가 수행하는 방법을 정의

. 특히

,이 부분을 보면 :

첫째, N라는 이름의 모든 접근 (3.5 절) 회원의 세트는 T에 선언 및 T의 기본 유형 (7.3.1)가 구성되어있다. 재정의 수정자를 포함하는 선언은 집합에서 제외됩니다.

귀하의 경우, NFoo()입니다. Declarations that include an override modifier are excluded from the set로 인해 override Foo(int i)은 집합에서 제외됩니다.

따라서 오버라이드되지 않은 Foo(double i) 만 남아 있으므로 호출 된 것입니다.

예를 들어 OverriddenDerivedClass의 경우 작동하는 방식이지만 DerivedClass 예는 설명이 아닙니다.

는 것을 설명하기 위해, 사양의이 부분을보고 :

다음으로, 다른 회원들에 의해 숨겨진 멤버는 집합에서 제거됩니다. 이 세트로부터 제거되도록

DerivedClassFoo(double i)는베이스 클래스로부터 Foo(int i) 숨어있다. M과 동일한 서명

모든 방법은 집합에서 제거 S의 기본 형식으로 선언 :

여기에 까다로운 것은

말한다 부분입니다.

"하지만 잠깐!Foo(double i)Foo(int i)과 동일한 서명을하지 않기 때문에이 세트에서 제거해서는 안됩니다! ".

을하지만, 두 배로 INT에서 암시 적 변환이 있기 때문에,이 것으로 간주됩니다 같은 서명은, 그래서 Foo(int i)은 세트에서 제거

+0

'((BaseClass) derived) .Foo (i)' – Corak

+0

을 포함하더라도 검색되지 않습니다. 그러나 실제로 : "T ...의 기본 유형 (7.3.1 절)은 BaseClass :: Foo (int)가 범위 내에 있음을 의미합니다. 집합이 다음과 같이 표시 될 수 있습니다. DerivedClass : : Foo (double), BaseClass :: Foo (int). 정수 인수를 취하면 암시 적으로 정수를 double로 변환 할 수 있음을 알게되고 BaseClass :: Foo (int)는 평가되지 않습니다. Foo (double) Foo (int)가있는 일반 클래스가 NormalClass : Foo (int), NormalClass : Foo (double)와 같은 집합을 가질 때 – Nebula

+0

@Nebula 죄송합니다. 그러나 기본'Foo (int)'는 범위 내에 있지만 유도 된 클래스'Foo (double)'와 동일한 서명을 가지고 있기 때문에 (int에서 double로 암시 적으로 변환되기 때문에) 파생 클래스의'Foo double)'은 기본 클래스의'Foo (int)'가 집합에서 제거되도록합니다. –