C #-키워드 사용 가상 + 재정의 vs.


204

기본 유형 " virtual" 에서 메소드를 선언 한 다음 하위 유형 에서 일치하는 메소드를 선언 할 때 override단순히 " new"키워드 를 사용하는 대신 " "키워드를 사용하여 하위 유형에서 메소드 를 대체하는 것의 차이점은 무엇입니까 ?


3
MSDN을 사용 new하면 "사용 하면 이름이 같은 새 멤버가 만들어지고 원래 멤버가 숨겨 override
지지만


답변:


181

"new"키워드는 재정의되지 않으며 기본 클래스 메소드와 관련이없는 새 메소드를 나타냅니다.

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

public class Test
{
    public static void Main ()
    {
        Foo test = new Bar ();
        Console.WriteLine (test.DoSomething ());
    }
}

재정의를 사용하면 true로 인쇄 될 수 있습니다.

(Joseph Daigle에서 가져온 기본 코드)

따라서 당신이 진정한 다형성을하고 있다면 항상 덮어야 합니다. "새"를 사용해야하는 유일한 방법은 메소드가 기본 클래스 버전과 관련이없는 경우입니다.


코드를 수정해야합니다. 메소드를 정적으로 만들었습니다 ( "new"키워드 사용에 유효 함). 그러나 인스턴스 메소드를 사용하는 것이 더 명확하다고 결정했습니다.
Joseph Daigle

1
감사합니다. "정적"부분을 놓쳤습니다. 미래에 더 많은 관심을 가지고해야
albertein

1
Foo test = new Bar () 줄은 여기서 중요합니다 .Meods에 대한 new / override 키워드는 Foo 변수에 Bar를 넣을 때 호출되는 metod를 결정합니다.
Thomas N

... 그래서 그것은 단순히 같은 동일한입니다 하지 가지는 virtual베이스와 override유래에? 왜 존재합니까? 코드는 여전히 실행되지 않습니다. new순전히 가독성이 좋습니까?
Don Cheadle

당신의 대답은 애매 모호합니다. new와 virtual-override는 똑같은 일을하지만 유일한 차이점은 new HIDES가 부모 클래스의 메서드를 재정의하고 재정의한다는 것입니다. 물론 테스트 객체가 Foo 유형이기 때문에 false를 인쇄합니다. Bar 유형이면 true를 인쇄합니다. 그래도 꽤 까다로운 예입니다.
MrSilent

228

나는 항상 이와 같은 것들을 그림으로 더 쉽게 이해합니다.

다시, 조셉 대글의 코드를 가져 와서

public class Foo
{
     public /*virtual*/ bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public /*override or new*/ bool DoSomething() { return true; }
}

그런 다음 다음과 같이 코드를 호출하십시오.

Foo a = new Bar();
a.DoSomething();

참고 : 중요한 것은 객체가 실제로 Bar이지만 변수 유형으로 저장한다는 것입니다Foo (이것은 캐스팅과 유사합니다)

당신이 사용 여부에 따라 다음과 같이 결과가 될 것입니다 virtual/ override또는 new클래스를 선언 할 때.

가상 / 재정의 설명 이미지


3
고마워 ....하지만 당신이 말한 캐스팅과 관련하여 위의 그림에 대해 조금 설명해 주시겠습니까?
odiseh

죄송합니다. 이전에이 몇 줄을 추가하지 않은 경우 의견 : 가상 / 재정의 및 비 Vivital / New는 다형성 개념에만 사용되며 단순히 캐스팅을 사용하지 않고 변수를 선언 할 때 의미하지 않습니까? 다시 감사합니다.
odiseh

이 답변은 내가 찾던 것입니다. 내가 가진 유일한 문제는 직장에서 플리커 이미지가 차단되어 전화로 액세스해야한다는 것입니다.
mezoid

7
질문에 대답하기위한 진정한 노력.
iMatoria

이미지를 고칠 수 있다면 투표를 하시겠습니까? 그것은 회사 방화벽 뒤에 차단되어 ...
제레미 톰슨

43

다음은 가상 및 비가 상 메소드의 동작 차이를 이해하기위한 코드입니다.

class A
{
    public void foo()
    {
        Console.WriteLine("A::foo()");
    }
    public virtual void bar()
    {
        Console.WriteLine("A::bar()");
    }
}

class B : A
{
    public new void foo()
    {
        Console.WriteLine("B::foo()");
    }
    public override void bar()
    {
        Console.WriteLine("B::bar()");
    }
}

class Program
{
    static int Main(string[] args)
    {
        B b = new B();
        A a = b;
        a.foo(); // Prints A::foo
        b.foo(); // Prints B::foo
        a.bar(); // Prints B::bar
        b.bar(); // Prints B::bar
        return 0;
    }
}

이것에 대해 감사합니다. 그러나 new단순히 override를 사용하지 않을 때 왜 기본 메소드를 "숨겨"사용하는 것이 똑같 을까요?
Don Cheadle

1
기본 클래스가 재정의되는 것을 막기 위해 만들어진 것 같지는 않습니다. 나는 그것이 충돌하지 않는 메소드를 오버라이드 할 수 없기 때문에 이름 충돌을 피하기 위해 만들어 졌다고 생각합니다 virtual. 컴파일러는 virtual서명 이없는 클래스 "bloodline"에서 동일한 함수 이름을 볼 경우 불평합니다
mr5

19

new키워드는 실제로 해당 특정 유형에 존재하는 완전히 새로운 멤버를 작성합니다.

예를 들어

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

이 방법은 두 가지 유형 모두에 존재합니다. 리플렉션을 사용하고 유형의 멤버를 가져 Bar오면 실제로 DoSomething()똑같이 보이는 두 개의 메소드가 있습니다. 를 사용 new하면 기본 클래스에서 구현을 효과적으로 숨길 수 있으므로 클래스가 Bar(내 예제에서) 파생 될 때 메소드 호출이 아닌 로 base.DoSomething()이동합니다 .BarFoo


9

virtual / override 는 컴파일러에게 두 가지 방법이 관련되어 있으며 어떤 상황에서는 첫 번째 (가상) 메소드를 호출한다고 생각할 때 실제로 두 번째 (재정의) 메소드를 호출하는 것이 맞다는 것을 컴파일러에게 알려줍니다. 이것이 다형성의 기초입니다.

(new SubClass() as BaseClass).VirtualFoo()

SubClass의 재정의 된 VirtualFoo () 메소드를 호출합니다.

new 는 컴파일러에게 기본 클래스의 메서드와 이름이 같은 파생 클래스에 메서드를 추가하고 있지만 서로 관계가 없다고 알려줍니다.

(new SubClass() as BaseClass).NewBar()

BaseClass의 NewBar () 메서드를 호출합니다.

(new SubClass()).NewBar()

SubClass의 NewBar () 메소드를 호출합니다.


이 문장처럼 "컴파일러에게 알려줍니다"
Mina Gabriel

"다형성의 기초"는 또 다른 고급스러운 말입니다 :)
Jeremy Thompson

8

기술적 세부 사항 외에도 가상 / 재정의를 사용하면 디자인에 대한 많은 의미 정보가 전달된다고 생각합니다. 가상 메소드를 선언 할 때 구현 클래스가 기본이 아닌 고유 한 구현을 제공하고자 할 수 있음을 나타냅니다. 마찬가지로 기본 클래스에서 이것을 생략하면 기본 메소드가 모든 구현 클래스에 충분해야한다는 기대를 선언합니다. 마찬가지로 추상 선언을 사용하여 구현 클래스가 자체 구현을 제공하도록 할 수 있습니다. 다시 말하지만, 이것은 프로그래머가 코드 사용을 어떻게 기대하는지에 대해 많은 의사 소통을한다고 생각합니다. 기본 클래스와 구현 클래스를 모두 작성하고 new를 사용하여 자신을 발견하면 부모에서 메소드를 가상으로 만들지 않고 내 의도를 구체적으로 선언하지 않기로 한 결정을 진지하게 다시 생각할 것입니다.


새로운 대 재정의에 대한 기술적 설명은 적절하지만이 답변은 사용할 개발자를 인도하는 데 가장 도움이되는 것 같습니다.
Sully

4

override 키워드와 new 키워드의 차이점은 전자가 메서드를 재정의하고 나중에 키워드를 재정의한다는 점입니다.

자세한 내용은 다음 링크를 확인하십시오.

MSDN기타


3
  • new키워드는 숨기기입니다. -런타임에 메소드를 숨기고 있음을 의미합니다. 출력은 기본 클래스 방법을 기반으로합니다.
  • override재정의합니다. -기본 클래스의 참조로 파생 클래스 메서드를 호출하고 있음을 의미합니다. 출력은 파생 클래스 방법을 기반으로합니다.

1

내 버전의 설명은 속성 을 사용 하여 차이점을 이해하는 데 도움이됩니다.

override충분히 간단 하죠? 기본 유형 은 상위 유형을 대체 합니다.

new아마도 오해의 소지가 있습니다. 속성을 사용하면 이해하기 쉽습니다.

public class Foo
{
    public bool GetSomething => false;
}

public class Bar : Foo
{
    public new bool GetSomething => true;
}

public static void Main(string[] args)
{
    Foo foo = new Bar();
    Console.WriteLine(foo.GetSomething);

    Bar bar = new Bar();
    Console.WriteLine(bar.GetSomething);
}

당신이이 알 수있는 디버거를 사용하여 Foo foo이 개 GetSomething 실제로 재산의 두 버전이 같은 특성을 Foo의와 Bar의를하고, 알고있는 사용 하나, C #을 "추천"현재 유형에 대한 속성입니다.

Bar 버전을 사용하려면 override를 사용하거나 Foo foo대신 사용했을 것입니다.

Bar bar완전히 새로운 동작을 원하기 때문에 1 만 있습니다.GetSomething


0

어떤 방법으로 메소드를 표시하지 않는 것은 다음을 의미합니다. 런타임 유형이 아닌 오브젝트의 컴파일 유형을 사용하여이 메소드를 바인드하십시오 (정적 바인딩).

다음과 같은 방법으로 메소드 표시 virtual: 컴파일 시간 유형 (동적 바인딩)이 아닌 오브젝트의 런타임 유형을 사용하여이 메소드를 바인드하십시오.

파생 클래스에서 기본 클래스 virtual메서드를 표시 override한다는 것은 다음을 의미합니다. 이는 개체의 런타임 유형 (동적 바인딩)을 사용하여 바인딩 할 메서드입니다.

파생 클래스에서 기본 클래스 virtual메서드를 표시하는 것은 다음을 new의미합니다. 이것은 기본 클래스에서 이름이 같은 메서드와 관련이없는 새로운 메서드이며 객체의 컴파일 시간 유형 (정적 바인딩)을 사용하여 바인딩해야합니다.

virtual파생 클래스에서 기본 클래스 메서드를 표시하지 않으면 다음을 의미합니다.이 메서드는 new(정적 바인딩) 으로 표시됩니다 .

메소드를 표시하는 것은 다음을 abstract의미합니다.이 메소드는 가상이지만 본문을 선언하지 않으며 클래스도 추상적입니다 (동적 바인딩).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.