메소드를 "가상"으로 선언하는 이유는 무엇입니까?
가상을 사용하면 어떤 이점이 있습니까?
답변:
Virtual을 사용하면 상속하는 클래스가 기본 클래스가 사용하는 메서드를 대체 할 수 있습니다.
public class Thingy
{
public virtual void StepA()
{
Console.Out.WriteLine("Zing");
}
public void Action()
{
StepA();
Console.Out.WriteLine("A Thingy in Action.");
}
}
public class Widget : Thingy
{
public override void StepA()
{
Console.Out.WriteLine("Wiggy");
}
}
class Program
{
static void Main(string[] args)
{
Thingy thingy = new Thingy();
Widget widget = new Widget();
thingy.Action();
widget.Action();
Console.Out.WriteLine("Press any key to quit.");
Console.ReadKey();
}
}
프로그램을 실행할 때 출력은 다음과 같습니다.
Zing
A Thingy in Action.
Wiggy
A Thingy in Action.
Widget이 Thingy 수준에서 정의 된 Action () 메서드를 호출했지만 내부적으로 Thingy가 Widget의 StepA () 메서드를 호출 한 방법에 주목하십시오.
기본적인 대답은 클래스 상속자에게 더 많은 유연성을 제공한다는 것입니다. 물론 수업을 잘 설계해야합니다. 그렇지 않으면 약한 혼란이 생길 수 있습니다.
virtual 키워드는 메서드 또는 속성 선언을 수정하는 데 사용되며,이 경우 메서드 또는 속성을 가상 멤버라고합니다. 가상 멤버의 구현은 파생 클래스의 재정의 멤버에 의해 변경 될 수 있습니다.
가상 메서드가 호출되면 개체의 런타임 유형에서 재정의 멤버를 확인합니다. 가장 많이 파생 된 클래스의 재정의 멤버가 호출되며 파생 클래스가 멤버를 재정의하지 않은 경우 원래 멤버 일 수 있습니다. (런타임 유형 및 대부분의 파생 된 구현에 대한 자세한 내용은 10.5.3 가상 메서드를 참조하십시오.)
기본적으로 메서드는 가상이 아닙니다. 비가 상 메서드는 재정의 할 수 없습니다.
다음 수정 자와 함께 가상 수정자를 사용할 수 없습니다.
정적 추상 재정의
가상 속성은 선언 및 호출 구문의 차이를 제외하고 추상 메서드처럼 작동합니다.
- 정적 속성에 가상 수정자를 사용하는 것은 오류입니다.
- 상속 된 가상 속성은 override 한정자를 사용하는 속성 선언을 포함하여 파생 클래스에서 재정의 할 수 있습니다.
클래스에서 파생 할 계획이 없더라도 클래스를 모의하기 위해 가상 메서드를 표시해야 할 수 있습니다. 일부 모의 프레임 워크는 가상 메서드를 모의하는 것만 허용합니다. 인터페이스를 구현하는 메서드는 암시 적으로 가상입니다.
저는 이러한 제한이있는 RhinoMocks를 사용하고 있으며 이러한 이유로 기본적으로 내 메서드를 가상으로 표시했습니다. 저에게있어 상속이 시작되는 경우가 훨씬 적기 때문에 가상 메서드를 사용하는 가장 큰 이유 일 것입니다.
여기에서는 C # Virtual Method 예제를 통해 명확하게 설명합니다.
가상 함수는 실제로 존재하지 않는 함수입니다. 파생 클래스는 가상 함수를 재정 의하여 수정할 수 있습니다. 가상 함수는 런타임 다형성을 달성하는 방법 중 하나입니다.
public class sample {
public virtual void fun(){
Console.WriteLine("base sample class \n");
}
}
public class A : sample{
public override void fun(){
Console.WriteLine("Class A \n");
}
}
public class B : sample{
public override void fun(){
Console.WriteLine("Class B \n");
}
}
class run{
public static void main(String[] args){
sample obj = new sample();
sample obj1 = new A();
sample obj2 = new B();
obj.fun();
obj1.fun();
obj2.fun();
}
}
public
액세스 후 수정 class A
및 class B
원인 오류 컴파일시. 파생 클래스의 기본 클래스에있는 멤버의 액세스 가능성은 기본 클래스 (기본적으로 멤버는 private
) 를 통해 개별적으로 지정됩니다 .
런타임은 컴파일 시간 동안 발생합니다.
메서드를 가상으로 선언 할 때 파생 클래스에서 선언하려면 override
또는 new
수정자를 추가해야합니다 .
우리는 TrySpeak
. 자식과 아버지를 전달하면 모두 Speak of father를 TryScream
호출하고는 각 메서드를 호출합니다.
이를 이해하기 위해 우리가 알아야 할 몇 가지 사항이 있습니다. Child 인스턴스에는 Scream
Child 클래스 또는 Father 클래스의 두 가지 메서드 가 있습니다 . Scream
from Child 클래스 나 Father 클래스 를 호출 할 수 있습니다 . Virtaul
Modifier는 파생 클래스에 의해 재정의 될 수 있도록 메서드를 표시 하기 때문에이 메서드 Scream
는 Father 클래스에서 호출 되어도 재정의되므로 새 수정자를 사용하면 달라집니다.
import system;
class Father
{
Speak()
{
Console.Writeline("Father is speaking")
}
virtual Scream()
{
Console.Writeline("Father is screaming")
}
}
class Child: father
{
Speak()
{
Console.Writeline("Child is speaking")
}
override Scream()
{
Console.Writeline("Child is screaming")
}
}
class APP
{
public static void Main()
{
// We new two instances here
Father father = new Father();
Child child = new Child();
// Here we call their scream or speak through TryScream or TrySpeak
TrySpeak(father);
TrySpeak(child);
//>>>"Father is speaking"
//>>>"Father is speaking"
TryScream(father);
TryScream(child);
//>>>"Father is screaming"
//>>>"Child is screaming"
}
// when your method take an Parameter who type is Father
// You can either pass in a Father instance or
// A instance of a derived Class from Father
// which could be Child
public static void TrySpeak(Father person)
{
person.Scream();
}
public static void TryScream(Father person)
{
person.Speak();
}
}
C #에서 파생 클래스의 기본 클래스 메서드를 재정의하려면 아래와 같이 기본 클래스 메서드를 가상으로 선언하고 파생 클래스 메서드를 재정의로 선언해야합니다.
using System;
namespace Polymorphism
{
class A
{
public virtual void Test() { Console.WriteLine("A::Test()"); }
}
class B : A
{
public override void Test() { Console.WriteLine("B::Test()"); }
}
class C : B
{
public override void Test() { Console.WriteLine("C::Test()"); }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
C c = new C();
a.Test(); // output --> "A::Test()"
b.Test(); // output --> "B::Test()"
c.Test(); // output --> "C::Test()"
a = new B();
a.Test(); // output --> "B::Test()"
b = new C();
b.Test(); // output --> "C::Test()"
Console.ReadKey();
}
}
}
파생 클래스의 메서드는 동시에 가상 및 새 메서드가 될 수 있으므로 virtual 및 new 키워드를 사용하여 메서드 숨김과 메서드 재정의를 혼합 할 수도 있습니다. 아래와 같이 클래스 C의 클래스 B, Test () 메서드를 재정의 할 때 파생 된 클래스 메서드를 다음 수준으로 추가 재정의하려는 경우 필요합니다.
using System;
namespace Polymorphism
{
class A
{
public void Test() { Console.WriteLine("A::Test()"); }
}
class B : A
{
public new virtual void Test() { Console.WriteLine("B::Test()"); }
}
class C : B
{
public override void Test() { Console.WriteLine("C::Test()"); }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
C c = new C();
a.Test(); // output --> "A::Test()"
b.Test(); // output --> "B::Test()"
c.Test(); // output --> "C::Test()"
a = new B();
a.Test(); // output --> "A::Test()"
b = new C();
b.Test(); // output --> "C::Test()"
Console.ReadKey();
}
}
}
황금 단어 : 가상 키워드는 기본 클래스에서 선언 된 메서드, 속성, 인덱서 또는 이벤트를 수정하고 파생 클래스에서 재정의 할 수 있도록하는 데 사용됩니다.
override 키워드는 기본 클래스의 가상 / 추상 메서드, 속성, 인덱서 또는 이벤트를 파생 클래스로 확장하거나 수정하는 데 사용됩니다.
new 키워드는 기본 클래스의 메서드, 속성, 인덱서 또는 이벤트를 파생 클래스로 숨기는 데 사용됩니다.
즐겨 :-)
이 링크는 매우 쉬운 예제 https://stackoverflow.com/a/2392656/3373865로 더 나은 이해를 제공합니다.