Menu
CoddyTech

Ключевые слова Virtual и Override

Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy. Урок 21 из 70.

Когда производный класс наследует метод, иногда нужно полностью изменить поведение этого метода. Ключевые слова virtual и override работают вместе, позволяя сделать это контролируемым образом.

Пометь метод как 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!

Хотя myPet объявлена как Animal, C# вызывает версию Dog метода Speak(). Это называется полиморфизмом времени выполнения — фактически вызываемый метод зависит от истинного типа объекта, а не от объявленного типа переменной.

Если ты хочешь расширить поведение, а не полностью заменить его, то в переопределённом методе можно по-прежнему вызвать базовую реализацию с помощью base.Speak().

challenge icon

Задание

Легко

Давайте создадим систему уведомлений, которая покажет, как производные классы могут полностью переопределять поведение базового класса с помощью ключевых слов virtual и override, а также продемонстрирует возможности полиморфизма во время выполнения.

Вы создадите три файла, чтобы упорядочить код:

  • Notification.cs: Определите класс Notification в пространстве имён Alerts. Этот базовый класс представляет общее уведомление со свойством Message (строка) и конструктором, который задаёт его значение. Добавьте метод virtual с именем Send(), который возвращает "Sending notification: {Message}".
  • EmailNotification.cs: Определите класс EmailNotification в пространстве имён Alerts, наследующий Notification. Добавьте свойство Recipient (строка) и конструктор, принимающий и сообщение, и получателя (используйте base, чтобы передать сообщение). Переопределите метод Send(), чтобы он возвращал "Emailing {Recipient}: {Message}".
  • SmsNotification.cs: Определите класс SmsNotification в пространстве имён Alerts, который также наследует Notification. Добавьте свойство PhoneNumber (строка) и конструктор, принимающий и сообщение, и номер телефона. Переопределите 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(). Это и есть полиморфизм во время выполнения!

Попробуйте сами

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Проверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C#