하위 클래스에서 구현할 때 추상 메소드 앞에 키워드를 대체해야하는 이유는 무엇입니까?


9

추상 클래스에서 상속되는 클래스를 만들 때 상속 된 추상 클래스를 구현할 때 override 키워드를 사용해야하는 이유는 무엇입니까?

public abstract class Person
{
    public Person()
    {

    }

    protected virtual void Greet()
    {
        // code
    }

    protected abstract void SayHello();
}

public class Employee : Person
{
    protected override void SayHello() // Why is override keyword necessary here?
    {
        throw new NotImplementedException();
    }

    protected override void Greet()
    {
        base.Greet();
    }
}

메소드는 부모 클래스에서 abstract로 선언되었으므로 부모 클래스에는 구현이 없으므로 키워드 재정의가 필요한 이유는 무엇입니까?




"상속 수정자는 상속 된 메소드, 속성, 인덱서 또는 이벤트의 추상 또는 가상 구현을 확장하거나 수정하는 데 필요합니다." docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/…
gunr2171

2
거기에 넣지 않으면 메소드를 재정의하는 대신 "숨김"하고 있기 때문입니다. 당신은 그 경고를받을 이유의 "그건 당신이 의도하는 경우, 사용 new방법 없음 재정의 기본 클래스의 방법"오류 keyword` ... 당신은 또한 얻을 것입니다. "
론 베이어에게

가상 메소드가있는 @RonBeyer는 그렇습니다. 그러나 추상적으로는 컴파일되지 않습니다.
Johnathan Barclay

답변:


14

추상 클래스에서 상속되는 클래스를 만들 때 상속 된 추상 클래스를 구현할 때 override 키워드를 사용해야하는 이유는 무엇입니까?

"왜?" 이와 같은 질문은 모호하기 때문에 대답하기 어려울 수 있습니다. 귀하의 질문은 " override키워드가 필요한 위치를 주장하기 위해 언어 디자인 중에 어떤 주장을 할 수 있습니까?" 라고 가정하겠습니다.

한 발 물러서서 시작합시다. Java와 같은 일부 언어에서는 메소드가 기본적으로 가상이며 자동으로 대체됩니다. C #의 디자이너는 이것을 알고 Java의 사소한 결함이라고 생각했습니다. C #은 "어리석은 부분이 제거 된 Java" 가 아니라 C # 의 디자이너는 C, C ++ 및 Java의 문제가있는 디자인 포인트에서 배우고 C #에서 복제하지 않기를 원했습니다.

C # 디자이너는 재정의를 가능한 버그의 원인으로 간주했습니다. 결국, 그것은 테스트 된 기존 코드의 동작변경 하는 방법 이며 위험합니다. 재정의는 우연히 또는 우연히 수행되어야하는 것이 아닙니다. 그것에 대해 열심히 생각하는 누군가설계 해야 합니다 . 그렇기 때문에 기본적으로 메서드가 가상이 아니며 메서드를 재정의한다고 말해야하는 이유가 있습니다.

이것이 기본적인 추론입니다. 이제 좀 더 진보 된 추론을 할 수 있습니다.

StriplingWarrior의 답변은 좀 더 진보 된 논쟁을 할 수있는 첫 걸음입니다. 파생 클래스의 작성자에게 기본 클래스에 대한 정보가없고 새로운 메서드를 만들려고 할 수 있으며 사용자가 실수로 재정의하도록 허용해서는 안됩니다 .

이 시점이 합리적이지만 다음과 같은 여러 가지 반론이 있습니다.

  • 파생 클래스의 저자 는 기본 클래스에 대한 모든 것을 알아야 할 책임이 있습니다 ! 그들은 그 코드를 재사용하고 있으며, 코드를 재사용하기 전에 철저히 이해하기 위해 실사를해야합니다.
  • 특정 시나리오에서 가상 방법은 추상적입니다. 재정의 하지 않으면 오류가 발생 하므로 작성자가 실수로 구현을 작성하지 않았을 가능성이 큽니다.

그런 다음이 시점에서 더욱 발전된 주장을하자. 어떤 상황에서 파생 클래스의 작성자가 기본 클래스의 역할을 알지 못해서 면제 될 수 있습니까? 다음 시나리오를 고려하십시오.

  • 기본 클래스 작성자는 추상 기본 클래스 B를 만듭니다.
  • 다른 팀의 파생 클래스 작성자는 메서드 M을 사용하여 파생 클래스 D를 만듭니다.
  • 기본 클래스 작성자는 기본 클래스 B를 확장하는 팀이 항상 메소드 M을 제공해야하므로 기본 클래스 작성자는 추상 메소드 M을 추가합니다.
  • 클래스 D를 다시 컴파일하면 어떻게됩니까?

우리가 일어나고 싶은 것은 D의 저자에게 뭔가 관련이 바뀌 었다는 정보가 있다는 것 입니다. 변경된 관련 사항은 M이 이제 요구 사항이며 해당 구현에 과부하가 발생해야한다는 것입니다. 기본 클래스에서 호출 될 수 있음을 알고 있으면 DM의 동작을 변경해야 할 수도 있습니다. 올바른 것은 "오, DM이 존재하고 BM을 확장합니다"라고 말하지 않는 것 입니다. 컴파일러가 올바른 일을하는 것은 실패 하고 "D의 저자 인 Hey는 더 이상 유효하지 않은이 가정을 확인하고 필요한 경우 코드를 수정하십시오"라고 말합니다.

당신의 예에서,이 가정 override이었다 옵션SayHello가 추상 메소드를 오버라이드 때문이다. 두 가지 가능성이 있습니다. (1) 코드 작성자가 추상 메서드를 재정의하려고하거나 (2) 다른 사람이 기본 클래스를 변경했기 때문에 재정의 메서드가 우연히 재정의 되고 코드가 미묘한 방식으로 잘못되었습니다. 선택 사항 이라면 이러한 가능성을 구별 할 수 없습니다override .

하지만 override되어 필요한 우리는 떨어져 세 가지 시나리오를 알 수 있습니다. 가능한 실수가 코드가있는 경우 다음 override됩니다 실종 . 그것은 의도적으로 무시되는 경우 override이다 존재 . 그리고 의도적으로하면 되지 다음 오버라이드 (override)하는 new것입니다 존재 . C #의 디자인을 통해 이러한 미묘한 차이를 만들 수 있습니다.

기억 보고는 개발자의 마음을 읽는 필요 컴파일러 오류 ; 컴파일러는 잘못된 코드 에서 작성자가 생각한 올바른 코드를 추론 하고 올바른 방향으로 오류를 표시해야합니다. 개발자가 생각한 것에 대한 코드를 남길 수있는 단서가 많을수록 컴파일러가 오류보고에서 더 잘 수행 할 수 있으므로 버그를 더 빨리 찾고 수정할 수 있습니다.

그러나 더 일반적으로 C #은 코드가 변경되는 세상을 위해 설계되었습니다 . "이상한"표시의 C #의 수많은 기능이 있다고 가정 할 때, 사실 그들은 개발자가 알려 때문이다 유효한 것으로 사용이 기본 클래스가 변경 되었기 때문에 무효가되었다. 이 버그 클래스를 "취약한 기본 클래스 실패"라고하며 C #에는이 실패 클래스에 대한 여러 가지 흥미로운 완화 방법이 있습니다.


4
정교한 감사합니다. "내부에서"누군가로부터 권위있는 목소리를내는 것이 좋으며, 간단하고 완전하게 설명하는 훌륭한 일을하기 때문에 항상 귀하의 답변에 감사드립니다.
StriplingWarrior

자세한 설명 감사합니다! 정말 감사합니다.
psj01

좋은 포인트! 언급 한 다른 완화 방법 중 일부를 열거 해 주시겠습니까?
aksh1618

3

부모 클래스에서 다른 메서드를 재정의할지 또는이 수준의 클래스 계층 구조에 고유 한 새 구현을 만들지 여부를 지정합니다. 프로그래머가 클래스에서 생성 한 것과 정확히 동일한 서명을 가진 부모 클래스에 메소드가 존재한다는 사실을 인식하지 못할 수 있으며, 이는 놀라운 결과를 초래할 수 있습니다.

추상적 인 메소드 추상 이 아닌 자식 클래스에서 재정의 되어야 한다는 것은 사실이지만 C #의 제작자는 아마도 당신이하려는 일에 대해 명시 적으로 밝히는 것이 더 낫다고 생각했을 것입니다.


이것은 언어 디자인 팀의 추론을 이해하기에 좋은 출발입니다. 팀이 여기에 표현한 아이디어로 시작하는 방법을 보여 주지만 한 걸음 더 나아가는 답변을 추가했습니다.
Eric Lippert

1

abstractC # 언어 사양에 따라 method는 구현이없는 가상 메서드 이므로 abstract 메서드는 암시 적으로 가상 메서드임을 의미합니다. 그리고 override당신이 볼 수 있듯이, 추상 또는 가상 구현을 확장하거나 수정하는 데 사용됩니다 여기에

다시 말하면 가상 메소드를 사용하여 일종의 후기 바인딩을 구현하는 반면 추상 메소드는 유형의 서브 클래스가 메소드를 명시 적으로 대체하도록합니다. 그 방법이 때, 요점 virtual, 그것은 수 있습니다 그것이 때, 오버라이드 (override) 할 수 abstract- 그것은 해야한다 오버라이드 (override)


1
나는 그 질문이 무엇을 하는가에 관한 것이 아니라 왜 명백해야하는지 생각합니다.
Johnathan Barclay

0

@StriplingWarrior의 답변에 추가하기 위해 기본 클래스에서 가상 메서드를 재정의하는 것과 일치하는 구문을 사용하는 것도 가능하다고 생각합니다.

public abstract class MyBase
{
    public virtual void MyVirtualMethod() { }

    public virtual void MyOtherVirtualMethod() { }

    public abstract void MyAbtractMethod();
}

public class MyDerived : MyBase
{
    // When overriding a virtual method in MyBase, we use the override keyword.
    public override void MyVirtualMethod() { }

    // If we want to hide the virtual method in MyBase, we use the new keyword.
    public new void MyOtherVirtualMethod() { }

    // Because MyAbtractMethod is abstract in MyBase, we have to override it: 
    // we can't hide it with new.
    // For consistency with overriding a virtual method, we also use the override keyword.
    public override void MyAbtractMethod() { }
}

따라서 C # 추상 메서드를 재정의하는 데 재정의 키워드가 필요하지 않도록 설계되었을 있지만 디자이너는 가상 메서드 재정의와 일관성이 없기 때문에 혼란 스러울 것이라고 결정했습니다.


Re : "디자이너는 가상 방법을 재정의하는 것과 일관성이 없기 때문에 혼란 스러울 것이라고 결정했습니다." 가상 메소드 M이있는 기본 클래스 B와 대체가있는 파생 클래스 D가 있다고 가정하십시오. 이제 B의 저자가 M을 추상화하기로 결정했다고 가정하자. 그것은 중대한 변화이지만, 아마도 그렇게 할 것입니다. 질문 : D 작성자가 override? 를 제거해야 합니까? 나는 대부분의 사람들이 D의 저자가 불필요한 코드 변경을하도록 강요하는 것에 동의하지 않는다고 생각한다. 그들의 수업은 괜찮습니다!
Eric Lippert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.