: 나는 꽤 OOP의 몇 가지 개념 사이의 혼동하고있어 virtual
, override
, new
와 sealed override
. 누구든지 차이점을 설명 할 수 있습니까?
파생 클래스 메서드를 사용 override
하는 경우 기본 클래스 메서드가 파생 클래스에 의해 재정의되도록 키워드를 사용할 수 있습니다 . 하지만 new
, 및 에 대해 잘 모르겠습니다 sealed override
.
답변:
가상 키워드는 방법, 재산, 인덱서 또는 이벤트 선언을 수정하고 파생 클래스에서 오버라이드 (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를 지정한 것과 동일하지만 컴파일러 경고도 표시됩니다 (기본 클래스에서 메서드를 숨기고 있다는 것을 알지 못할 수 있기 때문). 또는 실제로 재정의하고 싶을 수 있으며 키워드를 포함하는 것을 잊었습니다.)
재정의 속성 선언에는 봉인 된 수정자가 포함될 수 있습니다 . 이 수정자를 사용하면 파생 클래스가 속성을 더 이상 재정의하지 못합니다. 봉인 된 재산의 접근 자도 봉인됩니다.
Derived
개체 의 인스턴스를 만들고 참조를 Base
변수 에 저장합니다 . 이것은 객체도 Derived
객체 이기 때문에 유효합니다 Base
. 그것은 우리가 "사람"이 필요하다고 말하는 것과 같습니다. 그래서 우리는 사람이되는 "Johnny"를 얻습니다. 여기서도 같은 거래입니다.
Base b = new Derived()
그것은한다고 Base
클래스를 통해 액세스 할 수 있습니다 Derived class
A가 있기 때문에 참조 derived class
의 기본 클래스의 전문입니다. Derived
클래스는 a가 할 수있는 모든 작업 (예 : 기본 클래스 메서드 호출 등 )을 base class
수행 할 수 있습니다. 그러나 a Base class
는 자신이 Derived class
할 수 있는 작업을 수행 할 수 없습니다 . 따라서 Derived d = new Base()
정확하지는 않지만 Base b = new Derived()
정확합니다.
new
수정자를 사용하는 목적을 명확히 할 수 있습니까 hide a base class method
? 두 번째 예제에서 b.SomeOtherMethod()
호출은 기본 클래스 구현을 호출합니다 ( 파생 클래스의 메서드를 숨겼다 고 말할 수 있음 ). 이것이 전형적인 사용 예라면 new
, 호출자 가 할당 될 수있는 compile-time type
어떤 메소드가 아니라 메소드를 사용하기 위해 a의 변수를 가지려고 할 때 사용되는 것 같습니다 runtime types
.
모든 메서드는 재정의 가능 (= 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");
가상이 아닌 메서드 GetPersonType
가 Fiend
인스턴스에 의해 호출 되면 실제로 Person.GetPersonType
호출됩니다.
Console.WriteLine(friend.GetPersonType()); // "person"
가상 메소드 GetName
가 Friend
인스턴스에 의해 호출 되면 다음과 같이 호출됩니다 Friend.GetName
.
Console.WriteLine(friend.GetName()); // "Onotole"
가상 메소드 GetName
가 Person
인스턴스에 의해 호출 되면 다음과 같이 호출됩니다 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.GetName
때 Mike
호출 Mike.GetName
합니다. 두 방법 모두 가상이 아니기 때문에 여기에서는 런타임 조회가 수행되지 않습니다.
new
숨기고있는 메서드가 가상인지 여부에 관계없이 언제든지 메서드를 만들 수 있습니다 .
이것은 속성과 이벤트에도 적용됩니다-그것들은 그 아래에있는 메소드로 표현됩니다.
기본적으로 메소드는 선언하지 않는 한 파생 클래스에서 재정의 할 수 없습니다 virtual
, 또는 abstract
. virtual
수단을 호출하기 전에 새로운 구현 확인 과 abstract
같은 수단 있지만 모든 파생 클래스에서 재정의 될 보장됩니다. 또한 다른 곳에서 재정의 될 것이기 때문에 기본 클래스에서 구현이 필요하지 않습니다.
위의 예외는 new
수정 자입니다. 메서드가 선언되지 않았 virtual
거나 파생 클래스 abstract
의 new
수정자를 사용하여 다시 정의 할 수 있습니다 . 메서드가 기본 클래스에서 호출되면 기본 메서드가 실행되고 파생 클래스에서 호출되면 새 메서드가 실행됩니다. new
당신이 할 수있는 모든 키워드는 동일한 이름 을 가진 두 가지 방법을 갖는 것입니다 클래스 계층 구조에서 입니다.
마지막으로 sealed
수정자는 virtual
메서드 체인을 끊고 다시 재정의 할 수 없도록 만듭니다. 자주 사용되지는 않지만 옵션이 있습니다. 이전 클래스에서 각각 파생 된 3 개의 클래스 체인이 더 합리적입니다.
A -> B -> C
만약 A
갖는다 virtual
또는 abstract
인 방법 overridden
하여 B
, 다음은 막을 수 C
를 선언하여 다시 변경할 sealed
에서 B
.
sealed
에서도 사용되며 classes
여기서이 키워드를 일반적으로 접하게됩니다.
이게 도움이 되길 바란다.
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();
virtual
기본 클래스에서 사용 하고 재정의 Derived
하면 D (다형성)가 제공됩니다.override
없이 사용하면 오류가 발생합니다.virtual
Base
virtual
경고와 함께 'B'가 작성됩니다 (다형성이 수행되지 않았으므로).new
의 간단한 방법 전에를 Derived
.new
키워드는 또 다른 이야기입니다. 동일한 이름의 속성이 기본 클래스에 있다는 경고를 단순히 숨 깁니다.virtual
또는 new
둘 다 새 수정자를 제외하고 동일합니다.
new
와 override
같은 방법으로 재산 이전에 사용할 수 없습니다.
sealed
어떤 클래스 나 메서드도 잠그기 전에 Derived 클래스에서 사용되며 컴파일 시간 오류가 발생합니다.