2009-06-30 5 views

답변

1

: 객체 지향 프로그래밍

하는 가상 함수 또는 가상 메소드 이며 그 동작 가 동일한 갖는 함수에 의해 상속 클래스 내에서 대체 될 수있는 함수 또는 방법 서명.

7

다형성을 원할 때 다른 언어와 마찬가지입니다. 이것을위한 사용의 톤이 있습니다. 예를 들어 콘솔이나 파일 또는 다른 장치에서 입력을 읽는 방식을 추상화하려고합니다. 가상 함수를 사용하여 여러 구체 구현이 뒤 따르는 일반 판독기 인터페이스를 가질 수 있습니다.

4

프록시 방법. 런타임시에 겹쳐 쓰기 방법. 예를 들어, Hibernate는 이것을 사용하여 lazy loading을 지원한다.

1

예를 들어 기본 클래스 Params와 파생 클래스 집합이 있습니다. params에서 파생 된 가능한 모든 클래스를 저장하는 배열에서 동일한 연산을 수행 할 수 있기를 원합니다.

아무런 문제가 없습니다. 가상 메소드를 선언하고 Params 클래스에 몇 가지 기본 구현을 추가하고 파생 클래스에서 재정의하십시오. 이제 배열을 탐색하고 참조를 통해 메서드를 호출 할 수 있습니다. 올바른 메서드가 호출됩니다.

class Params { 
public: 
    virtual void Manipulate() { //basic impl here } 
} 

class DerivedParams1 : public Params { 
public: 
    override void Manipulate() { 
     base.Manipulate(); 
     // other statements here 
    } 
}; 

// more derived classes can do the same 

void ManipulateAll(Params[] params) 
{ 
    for(int i = 0; i < params.Length; i++) { 
     params[i].Manipulate(); 
    } 
} 
3

파생 클래스에 함수를 재정의 할 수 있음을 알리는 데 사용됩니다.

MSDN의 경우 좋은 예가 here입니다.

3

기본적으로 가상 멤버를 사용하면 다형성을 표현할 수 있으며 파생 클래스는 기본 클래스의 메서드와 동일한 서명을 가진 메서드를 가질 수 있으며 기본 클래스는 파생 클래스의 메서드를 호출합니다.

기본 예제 :

public class Shape 
{ 
    // A few example members 
    public int X { get; private set; } 
    public int Y { get; private set; } 
    public int Height { get; set; } 
    public int Width { get; set; } 

    // Virtual method 
    public virtual void Draw() 
    { 
     Console.WriteLine("Performing base class drawing tasks"); 
    } 
} 

class Circle : Shape 
{ 
    public override void Draw() 
    { 
     // Code to draw a circle... 
     Console.WriteLine("Drawing a circle"); 
     base.Draw(); 
    } 
} 
class Rectangle : Shape 
{ 
    public override void Draw() 
    { 
     // Code to draw a rectangle... 
     Console.WriteLine("Drawing a rectangle"); 
     base.Draw(); 
    } 
} 
class Triangle : Shape 
{ 
    public override void Draw() 
    { 
     // Code to draw a triangle... 
     Console.WriteLine("Drawing a triangle"); 
     base.Draw(); 
    } 
} 
+2

"이며 기본 클래스는 파생 클래스의 메서드를 호출합니다." 샘플 코드와 쌍을 이루는 매우 혼란 스럽다. 텍스트는 base.Draw가 파생 클래스 Draw 메서드를 호출하도록합니다 (결과적으로 StackOverflowException이 발생합니다). 나는 당신의 요지를 얻었지만 새로 온 사람은 그렇지 않을 수도 있습니다. 샘플 코드는 정말 훌륭합니다. 실행하면 어떤 일이 발생하는지 명확하게 보여줍니다. –

71

그래서 기본적으로 만약 당신의 조상 클래스에서 당신은 방법에 대한 특정 동작을합니다. 자손이 동일한 메소드를 사용하지만 다른 구현이있는 경우 으로 바꿀 수 있습니다. 가상 키워드가있는 경우.

using System; 
class TestClass 
{ 
    public class Dimensions 
    { 
     public const double pi = Math.PI; 
     protected double x, y; 
     public Dimensions() 
     { 
     } 
     public Dimensions (double x, double y) 
     { 
     this.x = x; 
     this.y = y; 
     } 

     public virtual double Area() 
     { 
     return x*y; 
     } 
    } 

    public class Circle: Dimensions 
    { 
     public Circle(double r): base(r, 0) 
     { 
     } 

     public override double Area() 
     { 
     return pi * x * x; 
     } 
    } 

    class Sphere: Dimensions 
    { 
     public Sphere(double r): base(r, 0) 
     { 
     } 

     public override double Area() 
     { 
     return 4 * pi * x * x; 
     } 
    } 

    class Cylinder: Dimensions 
    { 
     public Cylinder(double r, double h): base(r, h) 
     { 
     } 

     public override double Area() 
     { 
     return 2*pi*x*x + 2*pi*x*y; 
     } 
    } 

    public static void Main() 
    { 
     double r = 3.0, h = 5.0; 
     Dimensions c = new Circle(r); 
     Dimensions s = new Sphere(r); 
     Dimensions l = new Cylinder(r, h); 
     // Display results: 
     Console.WriteLine("Area of Circle = {0:F2}", c.Area()); 
     Console.WriteLine("Area of Sphere = {0:F2}", s.Area()); 
     Console.WriteLine("Area of Cylinder = {0:F2}", l.Area()); 
    } 
} 

편집 : 코멘트
내가 기본 클래스에서 가상 키워드를 사용하지 않는 경우에
질문, 그것은 작동합니까?

자손 클래스에서 override 키워드를 사용하면 작동하지 않습니다. 컴파일러 오류 CS0506을 생성합니다. '가상', '추상'또는 '재정의'로 표시되지 않으므로 상속 된 멤버 'function2'을 재정의 할 수 없습니다.

오버라이드를 사용하지 않으면 CS0108 'desc.Method()'경고는 상속 된 멤버 'base.Method()를 숨 깁니다. 숨기기를 의도 한 경우 new 키워드를 사용하십시오.

여기에 new 키워드를 넣으려면 이 숨어 있습니다.

new public double Area() 
    { 
    return 2*pi*x*x + 2*pi*x*y; 
    } 

파생 클래스의 가상 메소드를 대체하는 것이 의무입니까?
아니요, 메소드를 재정의하지 않으면, 하위 클래스가 상속하는 메소드를 사용합니다.

+3

기본 클래스에서 가상 키워드를 사용하지 않으면 어떻게됩니까? 작동할까요? 가상 클래스를 오버라이드하는 것은 강제적입니까? – Preeti

+4

@Pre 의견에 귀하의 질문에 대답했습니다 –

+1

감사합니다 John.now 분명합니다. – Preeti

3

이렇게하면 런타임에 바인딩을 구현할 수 있습니다. 즉, 컴파일 할 때 런타임에 결정할 객체의 멤버가 호출됩니다. Wikipedia을 참조하십시오.

55

가상 함수의 실제 사용법을 이해하는 핵심은 특정 클래스의 개체에 첫 번째 개체 클래스에서 파생 된 클래스의 다른 개체를 할당 할 수 있다는 점을 기억하는 것입니다.

예컨대 :

class Animal { 
    public void eat() {...} 
} 

class FlyingAnimal : Animal { 
    public void eat() {...} 
} 

Animal a = new FlyingAnimal(); 

Animal 클래스 (예를 들어 입의 목적을두고 삼키기)은 일반적으로 동물은 먹는 방법을 설명하는 기능 eat()있다.

그러나 비행 동물은 특별한 식사 방법을 가지고 있기 때문에 FlyingAnimal 클래스는 새로운 eat() 메서드를 정의해야합니다.

그래서 여기에 떠오르는 질문은 : I 형 Animal의 변수 a을 선언 a.eat()가 무엇을 할 것인가, 그 유형 FlyingAnimal의 새로운 객체 asigned 후? 두 가지 방법 중 어느 것을 호출합니까?

여기에 대한 대답은 aAnimal 유형이므로 Animal의 메서드를 호출합니다. 컴파일러는 바보이며 다른 클래스의 객체를 a 변수에 할당한다는 것을 알지 못합니다.

여기에 virtual 키워드가 작동하는 곳이 있습니다.이 방법을 virtual void eat() {...}으로 선언하면 기본적으로 컴파일러에게 "내가 똑똑하지 않아서 처리 할 수없는 영리한 것들을 여기에서하고 있다고주의하십시오. ". 따라서 컴파일러는 a.eat()을 두 메서드 중 하나에 연결하려고 시도하지 않고 대신 시스템에 을 수행하도록 지시합니다!

그래서 코드 만 실행하면 시스템은 a 볼의 콘텐츠 형식되지 선언 된 유형에서와 FlyingAnimal 실행의 방법을합니다.

당신은 궁금해 할 수 있습니다. 왜 도대체 내가 그걸하고 싶습니까? 왜 시작부터 바로 말하지 않을까요 FlyingAnimal a = new FlyingAnimal()?

그 이유는 예를 들어, 당신은 Animal에서 여러 파생 클래스를 가질 수 있다는 것입니다

: FlyingAnimal, SwimmingAnimal, BigAnimal, WhiteDog 등그리고 한 지점에서 당신은 많은 Animal를 보관 세계를 정의 할, 그래서 당신은 말 :

Animal[] happy_friends = new Animal[100]; 

우리는 100 개 행복 동물 세계를 가지고있다.

... 
happy_friends[2] = new AngryFish(); 
... 
happy_friends[10] = new LoudSnake(); 
... 

을 그리고 하루의 끝에, 당신은 그들이 잠자리에 가기 전에 모두가 먹고 싶은 : 당신은 어떤 시점에서 그들을 초기화합니다. 따라서 다음과 같이 말하고 싶습니다.

for (int i=0; i<100; i++) { 
    happy_friends[i].eat(); 
} 

이렇게 각 동물마다 고유 한 식사 방법이 있습니다. 가상 기능 만 사용하면이 기능을 사용할 수 있습니다. 그렇지 않으면 모든 사람이 똑같은 방식으로 "먹는"것을 강요 받게됩니다 : 가장 일반적 인 eat 함수에 설명 된대로 Animal 클래스에 함수가 있습니다.

편집 : 이 동작은 실제로 기본값 인과 같은 일반적인 고급 언어로 Java입니다. C#에서 가상 함수의

+6

그래서 Animal을 대신 인터페이스로 만들까요? 모든 동물들이 사용할 수있는 동물 기초 기능이 있기 때문에? – Djorge

+1

@Djorge 바로. –

+1

감사합니다 아주 좋은 설명. 우수 답변! :) – wenn32

1

사용은

가상 기능은 대부분 동일한 서명으로 파생 클래스에서 기본 클래스 메서드를 재정의하는 데 사용됩니다.

파생 클래스가 기본 클래스를 상속하는 경우 파생 클래스의 개체는 파생 클래스 또는 기본 클래스에 대한 참조입니다.

가상 기능 (예 : 런타임 바인딩) 기본 클래스에서

virtual을, 함수의 대부분의 파생 클래스의 구현이 언급 된 객체의 실제 타입에 따라 호출되는 컴파일러에 의해 늦게 해결 포인터 또는 참조의 선언 된 유형에 관계없이 virtual이 아닌 경우 메서드는 early으로 결정되고 호출 된 함수는 포인터 또는 참조의 선언 된 유형에 따라 선택됩니다.

관련 문제