가상, 재정의, 신규 및 봉인 재정의의 차이점


79

: 나는 꽤 OOP의 몇 가지 개념 사이의 혼동하고있어 virtual, override, newsealed override. 누구든지 차이점을 설명 할 수 있습니까?

파생 클래스 메서드를 사용 override하는 경우 기본 클래스 메서드가 파생 클래스에 의해 재정의되도록 키워드를 사용할 수 있습니다 . 하지만 new, 및 에 대해 잘 모르겠습니다 sealed override.

답변:


107

가상 키워드는 방법, 재산, 인덱서 또는 이벤트 선언을 수정하고 파생 클래스에서 오버라이드 (override) 할 수 있도록하는 데 사용됩니다. 예를 들어,이 메서드는 상속하는 모든 클래스에서 재정의 할 수 있습니다. new 한정자를 사용하여 기본 클래스에서 상속 된 멤버를 명시 적으로 숨 깁니다. 상속 된 멤버를 숨기려면 동일한 이름을 사용하여 파생 클래스에서 선언하고 새 수정 자로 수정합니다.

이것은 다형성과 관련이 있습니다. 참조에서 가상 메서드가 호출 될 때 참조가 참조하는 개체의 실제 유형을 사용하여 사용할 메서드 구현을 결정합니다. 파생 클래스에서 기본 클래스의 메서드가 재정의되면 호출 코드가 개체가 파생 클래스의 인스턴스라는 것을 "인식"하지 못한 경우에도 파생 클래스의 버전이 사용됩니다. 예를 들면 :

public class Base
{
  public virtual void SomeMethod()
  {
  }
}

public class Derived : Base
{
  public override void SomeMethod()
  {
  }
}

...

Base d = new Derived();
d.SomeMethod();

Base.SomeMethod를 재정의하면 Derived.SomeMethod를 호출하게됩니다.

이제 override 대신 new 키워드 를 사용하면 파생 클래스의 메서드가 기본 클래스의 메서드를 재정의하지 않고 숨길뿐입니다. 이 경우 다음과 같이 코드를 작성하십시오.

public class Base
{
  public virtual void SomeOtherMethod()
  {
  }
}

public class Derived : Base
{
  public new void SomeOtherMethod()
  {
  }
}

...


Base b = new Derived();
Derived d = new Derived();
b.SomeOtherMethod();
d.SomeOtherMethod();

먼저 Base.SomeOtherMethod를 호출 한 다음 Derived.SomeOtherMethod를 호출합니다. 이는 기본 메서드를 재정의하는 파생 메서드가 아니라 동일한 이름을 갖는 사실상 완전히 별개의 두 메서드입니다.

new 또는 override를 지정하지 않으면 결과 출력은 new를 지정한 것과 동일하지만 컴파일러 경고도 표시됩니다 (기본 클래스에서 메서드를 숨기고 있다는 것을 알지 못할 수 있기 때문). 또는 실제로 재정의하고 싶을 수 있으며 키워드를 포함하는 것을 잊었습니다.)

재정의 속성 선언에는 봉인 된 수정자가 포함될 수 있습니다 . 이 수정자를 사용하면 파생 클래스가 속성을 더 이상 재정의하지 못합니다. 봉인 된 재산의 접근 자도 봉인됩니다.


입력 해 주셔서 감사합니다.하지만 내 마음에 들지 않는 것은 ..Base b = new Derived ()의 사용은 무엇입니까? 이것은 기본 클래스 또는 파생 클래스의 생성 개체입니까 ??
xorpower 2015 년

2
파생 클래스. 다형성에 대해 더 자세히 살펴 봐야한다고 생각합니다. 여기 당신의 읽기에 좋은 것입니다. msdn.microsoft.com/en-us/library/ms173152(v=vs.80).aspx
CharithJ

5
@Xor :이 경우 Derived개체 의 인스턴스를 만들고 참조를 Base변수 에 저장합니다 . 이것은 객체도 Derived객체 이기 때문에 유효합니다 Base. 그것은 우리가 "사람"이 필요하다고 말하는 것과 같습니다. 그래서 우리는 사람이되는 "Johnny"를 얻습니다. 여기서도 같은 거래입니다.
Jeff Mercado

여기에 한 점만 추가하고 싶습니다. Base b = new Derived()그것은한다고 Base클래스를 통해 액세스 할 수 있습니다 Derived classA가 있기 때문에 참조 derived class의 기본 클래스의 전문입니다. Derived클래스는 a가 할 수있는 모든 작업 (예 : 기본 클래스 메서드 호출 등 )을 base class수행 할 수 있습니다. 그러나 a Base class는 자신이 Derived class할 수 있는 작업을 수행 할 수 없습니다 . 따라서 Derived d = new Base()정확하지는 않지만 Base b = new Derived()정확합니다.
mmushtaq

new수정자를 사용하는 목적을 명확히 할 수 있습니까 hide a base class method? 두 번째 예제에서 b.SomeOtherMethod()호출은 기본 클래스 구현을 호출합니다 ( 파생 클래스의 메서드를 숨겼다 고 말할 수 있음 ). 이것이 전형적인 사용 예라면 new, 호출자 가 할당 될 수있는 compile-time type어떤 메소드가 아니라 메소드를 사용하기 위해 a의 변수를 가지려고 할 때 사용되는 것 같습니다 runtime types.
Minh Tran

35

모든 메서드는 재정의 가능 (= virtual) 가능하거나 불가능할 수 있습니다 . 결정은 방법을 정의하는 사람이 내립니다.

class Person
{
    // this one is not overridable (not virtual)
    public String GetPersonType()
    {
        return "person";
    }

    // this one is overridable (virtual)
    public virtual String GetName()
    {
        return "generic name";
    }
}

이제 재정의 가능한 메서드를 재정의 할 수 있습니다.

class Friend : Person
{
    public Friend() : this("generic name") { }

    public Friend(String name)
    {
        this._name = name;
    }

    // override Person.GetName:
    public override String GetName()
    {
        return _name;
    }
}

그러나 GetPersonType가상이 아니기 때문에 메서드를 재정의 할 수 없습니다 .

이러한 클래스의 두 인스턴스를 만들어 보겠습니다.

Person person = new Person();
Friend friend = new Friend("Onotole");

가상이 아닌 메서드 GetPersonTypeFiend인스턴스에 의해 호출 되면 실제로 Person.GetPersonType호출됩니다.

Console.WriteLine(friend.GetPersonType()); // "person"

가상 메소드 GetNameFriend인스턴스에 의해 호출 되면 다음과 같이 호출됩니다 Friend.GetName.

Console.WriteLine(friend.GetName()); // "Onotole"

가상 메소드 GetNamePerson인스턴스에 의해 호출 되면 다음과 같이 호출됩니다 Person.GetName.

Console.WriteLine(person.GetName()); // "generic name"

비가 상 메서드가 호출되면 메서드 본문이 조회되지 않습니다. 컴파일러는 호출해야하는 실제 메서드를 이미 알고 있습니다. 반면에 가상 메소드 컴파일러는 호출 할 것을 확신 할 수 없으며, 메소드가 호출되는 인스턴스 유형에서 시작하여 아래에서 위로 클래스 계층 구조에서 런타임시 friend.GetName조회됩니다.Friend 클래스와 그것은 바로, 대한 발견 person.GetName클래스가 시작 Person거기 발견을.

때로는 하위 클래스를 만들고 가상 메서드를 재정의하고 계층 구조에서 더 이상 재정의를 원하지 않습니다.이를 sealed override위해 사용 합니다 (당신이 메서드를 재정의하는 마지막 사람이라고 말함).

class Mike : Friend
{
    public sealed override String GetName()
    {
        return "Mike";
    }
}

하지만 때때로 당신의 친구 Mike가 그의 성별을 변경하기로 결정하여 그의 이름을 Alice로 변경합니다.

class Alice : Mike
{
    public new String GetName()
    {
        return "Alice";
    }
}

여기서는 동일한 이름으로 완전히 다른 방법을 만듭니다 (이제 두 가지가 있습니다). 어떤 방법과 언제 호출됩니까? 어떻게 부르 느냐에 따라 다릅니다.

Alice alice = new Alice();
Console.WriteLine(alice.GetName());             // the new method is called, printing "Alice"
Console.WriteLine(((Mike)alice).GetName());     // the method hidden by new is called, printing "Mike"

Alice의 관점 에서 호출 할 때 호출 할 Alice.GetNameMike호출 Mike.GetName합니다. 두 방법 모두 가상이 아니기 때문에 여기에서는 런타임 조회가 수행되지 않습니다.

new숨기고있는 메서드가 가상인지 여부에 관계없이 언제든지 메서드를 만들 수 있습니다 .

이것은 속성과 이벤트에도 적용됩니다-그것들은 그 아래에있는 메소드로 표현됩니다.


1
내가 어디서나 찾은 것보다 간단하고 완전한 대답은 없습니다. 감사합니다 Loki
Reevs

19

기본적으로 메소드는 선언하지 않는 한 파생 클래스에서 재정의 할 수 없습니다 virtual, 또는 abstract. virtual수단을 호출하기 전에 새로운 구현 확인abstract같은 수단 있지만 모든 파생 클래스에서 재정의 될 보장됩니다. 또한 다른 곳에서 재정의 될 것이기 때문에 기본 클래스에서 구현이 필요하지 않습니다.

위의 예외는 new수정 자입니다. 메서드가 선언되지 않았 virtual거나 파생 클래스 abstractnew수정자를 사용하여 다시 정의 할 수 있습니다 . 메서드가 기본 클래스에서 호출되면 기본 메서드가 실행되고 파생 클래스에서 호출되면 새 메서드가 실행됩니다. new당신이 할 수있는 모든 키워드는 동일한 이름 을 가진 두 가지 방법을 갖는 것입니다 클래스 계층 구조에서 입니다.

마지막으로 sealed수정자는 virtual메서드 체인을 끊고 다시 재정의 할 수 없도록 만듭니다. 자주 사용되지는 않지만 옵션이 있습니다. 이전 클래스에서 각각 파생 된 3 개의 클래스 체인이 더 합리적입니다.

A -> B -> C

만약 A갖는다 virtual또는 abstract인 방법 overridden하여 B, 다음은 막을 수 C를 선언하여 다시 변경할 sealed에서 B.

sealed에서도 사용되며 classes여기서이 키워드를 일반적으로 접하게됩니다.

이게 도움이 되길 바란다.


8
 public class Base 
 {
   public virtual void SomeMethod()
   {
     Console.WriteLine("B");
   }
  }

public class Derived : Base
{
   //Same method is written 3 times with different keywords to explain different behaviors. 


   //This one is Simple method
  public void SomeMethod()
  {
     Console.WriteLine("D");
  }

  //This method has 'new' keyword
  public new void SomeMethod()
  {
     Console.WriteLine("D");
  }

  //This method has 'override' keyword
  public override void SomeMethod()
  {
     Console.WriteLine("D");
  }
}

이제 먼저 먼저

 Base b=new Base();
 Derived d=new Derived();
 b.SomeMethod(); //will always write B
 d.SomeMethod(); //will always write D

이제 키워드는 다형성에 관한 것입니다.

 Base b = new Derived();
  1. virtual기본 클래스에서 사용 하고 재정의 Derived하면 D (다형성)가 제공됩니다.
  2. in override없이 사용하면 오류가 발생합니다.virtualBase
  3. 비슷하게 메서드를 작성하면 (무효화) virtual경고와 함께 'B'가 작성됩니다 (다형성이 수행되지 않았으므로).
  4. 위의 포인트 쓰기에서와 같이 경고 숨기려면 new의 간단한 방법 전에를 Derived.
  5. new 키워드는 또 다른 이야기입니다. 동일한 이름의 속성이 기본 클래스에 있다는 경고를 단순히 숨 깁니다.
  6. virtual또는 new둘 다 새 수정자를 제외하고 동일합니다.

  7. newoverride같은 방법으로 재산 이전에 사용할 수 없습니다.

  8. sealed 어떤 클래스 나 메서드도 잠그기 전에 Derived 클래스에서 사용되며 컴파일 시간 오류가 발생합니다.

미안하지만, -1 여러 컴파일 에러의 이유는 방법은 동일한 매개 변수를 여러 번 선언, 문자열 B & D ... 주위에 따옴표 없습니다
DeveloperDan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.