Menu
Coddy logo textTech

Virtual 및 Override 키워드

Coddy C# 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 70개 중 21번째.

파생 클래스가 메서드를 상속받을 때, 때로는 그 메서드가 동작하는 방식을 완전히 바꾸고 싶을 때가 있습니다. virtualoverride 키워드는 제어된 방식으로 이를 가능하게 하기 위해 함께 작동합니다.

기본 클래스에서 메서드를 virtual로 표시하여 파생 클래스가 해당 구현을 재정의할 수 있음을 나타냅니다:

public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Some sound");
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

파생 클래스의 override 키워드는 기본 메서드를 의도적으로 재정의하고 있음을 컴파일러에게 알려줍니다. 기본 메서드에 virtual이 없으면 override를 사용할 수 없습니다.

기본 클래스 참조를 사용하여 파생 객체를 보유할 때 진정한 힘이 나타납니다:

Animal myPet = new Dog();
myPet.Speak();  // 출력: Woof!

myPetAnimal로 선언되었음에도 불구하고, C#은 Dog 버전의 Speak()를 호출합니다. 이것을 런타임 다형성(runtime polymorphism)이라고 합니다. 실제로 호출되는 메서드는 변수의 선언된 타입이 아니라 객체의 실제 타입에 따라 결정됩니다.

동작을 완전히 대체하기보다는 확장하고 싶은 경우, 오버라이드 내부에서 base.Speak()를 사용하여 기본 구현에 여전히 접근할 수 있습니다.

challenge icon

챌린지

쉬움

virtualoverride 키워드를 사용하여 파생 클래스가 기본 클래스의 동작을 완전히 재정의하는 방법을 보여주는 알림 시스템을 구축해 보겠습니다. 또한 런타임 다형성(runtime polymorphism)의 강력함도 함께 살펴보겠습니다.

코드를 구성하기 위해 세 개의 파일을 생성합니다:

  • Notification.cs: Alerts 네임스페이스 내에 Notification 클래스를 정의합니다. 이 기본 클래스는 Message 속성(string)과 이를 설정하는 생성자를 가진 일반적인 알림을 나타냅니다. "Sending notification: {Message}"를 반환하는 Send()라는 virtual 메서드를 포함하세요.
  • EmailNotification.cs: Notification을 상속받는 EmailNotification 클래스를 Alerts 네임스페이스 내에 정의합니다. Recipient 속성(string)을 추가하고 메시지와 수신자를 모두 받는 생성자를 만듭니다 (메시지를 전달하려면 base를 사용하세요). Send() 메서드를 재정의(override)하여 "Emailing {Recipient}: {Message}"를 반환하도록 합니다.
  • SmsNotification.cs: 마찬가지로 Notification을 상속받는 SmsNotification 클래스를 Alerts 네임스페이스 내에 정의합니다. PhoneNumber 속성(string)을 추가하고 메시지와 전화번호를 모두 받는 생성자를 만듭니다. Send()를 재정의하여 "SMS to {PhoneNumber}: {Message}"를 반환하도록 합니다.
  • Program.cs: 메인 파일에서 입력 값을 사용하여 세 가지 알림 유형의 인스턴스를 모두 생성합니다. 그런 다음 세 인스턴스를 모두 Notification 변수에 저장하고 각각에 대해 Send()를 호출하여 런타임 다형성을 증명하세요.

네 가지 입력을 받게 됩니다:

  • 알림 메시지
  • 이메일 수신자 주소
  • SMS용 전화번호

기본 클래스 참조로 저장된 각 알림에 대해 Send()를 호출한 결과를 출력하세요:

{base notification Send() result}
{email notification Send() result}
{sms notification Send() result}

예를 들어, 입력값이 Meeting at 3pm, alice@email.com, 555-1234라면 출력은 다음과 같아야 합니다:

Sending notification: Meeting at 3pm
Emailing alice@email.com: Meeting at 3pm
SMS to 555-1234: Meeting at 3pm

세 가지 모두 Notification 변수로 저장되었음에도 불구하고, 각자 재정의된 버전의 Send()를 호출하는 방식에 주목하세요. 이것이 바로 실행 중인 런타임 다형성입니다!

치트 시트

기본 클래스에서 virtual 키워드를 사용하여 파생 클래스가 재정의(override)할 수 있는 메서드를 표시합니다:

public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Some sound");
    }
}

파생 클래스에서 override 키워드를 사용하여 기본 클래스 메서드 구현을 대체합니다:

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

런타임 다형성(Runtime polymorphism)은 기본 클래스 참조가 파생 개체를 보유할 때 발생합니다. 실제로 호출되는 메서드는 변수의 선언된 형식이 아니라 개체의 실제 형식에 따라 결정됩니다:

Animal myPet = new Dog();
myPet.Speak();  // 출력: Woof!

base를 사용하여 재정의된 메서드 내부에서 기본 구현에 액세스할 수 있습니다:

public override void Speak()
{
    base.Speak();  // 기본 클래스 버전을 호출합니다
    Console.WriteLine("Woof!");
}

직접 해보기

using System;
using Alerts;

class Program
{
    public static void Main(string[] args)
    {
        // 입력 읽기
        string message = Console.ReadLine();
        string email = Console.ReadLine();
        string phone = Console.ReadLine();

        // TODO: 세 가지 알림 유형의 인스턴스 모두 생성하기
        // 다형성을 보여주기 위해 Notification 변수에 저장하기
        
        // TODO: 기본 Notification 생성하기
        Notification baseNotification;
        
        // TODO: EmailNotification 생성하기 (Notification 타입으로 저장)
        Notification emailNotification;
        
        // TODO: SmsNotification 생성하기 (Notification 타입으로 저장)
        Notification smsNotification;
        
        // TODO: 각각에 대해 Send()를 호출하고 결과 출력하기
        // 런타임 다형성으로 인해 오버라이드된 메서드들이 호출될 것입니다
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨