2013-01-24 1 views
1
class Program 
{ 
    static void Main(string[] args) 
    { 
     B foo = new B(); 
     foo.DoWork(); 
     Console.ReadLine(); 
    } 
} 

public class A 
{ 
    public virtual void DoWork() { Console.WriteLine("A"); } 
} 
public class B : A 
{ 
    public override void DoWork() { base.DoWork(); Console.WriteLine("B"); } 
} 

왜 StackOverflow 예외가 발생합니까? 내가 이해하는 것처럼, foo.DoWork()가 불려지면 B.DoWork() 메서드에서 오버라이드 된 virtual 인 base.DoWork()가 호출되어 스택이 오버플로 될 때까지 base.DoWork()를 다시 반복한다. . 이 overflow는 base (self를 호출하는 순환 루프) 대신에 이것을 사용할 때 쉽게 얻을 수 있습니다. 이 경우 가상 함수 오버라이드를 방지하는 것은 무엇입니까?오버 라이딩 및 가상 함수 호출에서 stackoverflow 예외가 발생하지 않는 이유는 무엇입니까?

+0

이것이'base'의 작동 방식이라면, 언제든지 그것을 사용하면 언제든지 stackoverflow가 될 것이고, 언어로 사용하게 될 이유가 전혀 없을 것입니다. – Servy

+0

@Servy 아니, 문제없이 기본을 사용하여 비 가상 메서드를 호출 할 수 있습니다. 이것은 가상 메서드로 기본을 사용하는 특별한 경우입니다. – user206334

+0

기본 클래스의 비가 상 메소드를 호출하려면 'this'를 기본 클래스에 캐스트하고 메소드를 호출하십시오. 'base'는'base' 없이는 할 수 없기 때문에 가상 메소드의 기본 클래스의 버전을 호출하도록 특별히 설계되었습니다.'base'의 다른 용도는 그 키워드없이 할 수 있습니다. – Servy

답변

11

아니요, base을 사용하는 경우 으로 가상 전화를 걸지 않습니다. 요점은을 재정의 한 경우에도 base 구현 으로 전화 할 수 있다는 것입니다.

당신이 생성 된 IL을 보면, 당신이 callvirt 사용하지 않는 볼 수 있습니다 :

다음 C# 5 사양 (강조 광산)의 섹션 7.6.8에서

IL_0002: call  instance void A::DoWork() 

기본 액세스가 가상 함수 멤버 (메서드, 속성 또는 인덱서)를 참조하면 런타임에 호출 할 함수 멤버 (§7.5.4)의 결정이 변경됩니다. 호출 된 함수 멤버는 B에 대한 함수 멤버의 가장 파생 된 구현 (§10.6.3)을 찾아서 결정됩니다 (런타임 유형이 아닌 일반 베이스 액세스). 따라서 가상 함수 멤버의 재정의 내에서 기본 액세스를 사용하여 함수 멤버의 상속 된 구현을 호출 할 수 있습니다. 기본 액세스가 참조하는 함수 멤버가 추상 클래스이면 바인딩 타임 오류가 발생합니다.

+0

[Eric Lippert는 다음과 같이 썼습니다 (http://blogs.msdn.com/b/ericlippert/archive/2010/03/29/putting-a-base-in-the-middle.aspx) C# 직접 기본 클래스 대신 실제로 구현 된 가장 파생 된 기본 클래스를 찾습니다. –

+0

@BenVoigt : (나는 거의 정확히 같은 시간에 그것을 발견했다. :) –

+0

예. 방금이 토론과 관련이 있다고 생각했습니다. –

1

가상 메서드는 재정의 될 수 있고 코드가 포함 된 메서드 일뿐입니다. base.DoWork()으로 전화 할 때 A.DoWork()으로 전화하겠다고 명시 적으로 명시하십시오. 그런 다음 A.DoWork()이 호출됩니다.

A.DoWork() 추상화하면 코드를 포함 할 수 없습니다. 그런 다음 base.DoWork()에 실행할 것이 없기 때문에 base.DoWork()에 컴파일 오류가 발생합니다.

+1

오버로드 됨! = 재정의 됨. 여기서 재정의한다는 의미입니다. –

2

A.DoWork은 가상입니다. 그러나 base.으로 명명 된 방법은 이 아니며 가상입니다. 이 구문은 가상이 아닌 호출을 생성하므로 정확한 메서드가 호출되며 가장 파생 된 버전이 호출되지 않습니다.

관련 문제