Когда мы создаем класс, который наследуется от абстрактного класса, и когда мы реализуем унаследованный абстрактный класс, почему мы должны использовать ключевое слово override?
"Почему?" На подобные вопросы трудно ответить, потому что они расплывчаты. Я буду считать , что ваш вопрос «какие аргументы могут быть сделаны во время разработки языка , чтобы отстаивать позицию , что overrideэто ключевое слово требуется ?»
Давайте начнем с шага назад. В некоторых языках, например, Java, методы являются виртуальными по умолчанию и переопределяются автоматически. Разработчики C # знали об этом и считали это незначительным недостатком Java. C # - это не «Java с удаленными глупыми частями», как говорили некоторые, но разработчики C # стремились извлечь уроки из проблемных аспектов проектирования C, C ++ и Java, а не копировать их в C #.
Разработчики C # считали переопределение возможным источником ошибок; в конце концов, это способ изменить поведение существующего, протестированного кода , и это опасно. Переопределение не является чем-то, что должно быть сделано случайно или случайно; это должно быть разработано кем-то, думающим об этом . Вот почему методы не являются виртуальными по умолчанию, и поэтому вы должны сказать, что вы переопределяете метод.
Это основные рассуждения. Теперь мы можем перейти к более сложным рассуждениям.
Ответ StriplingWarrior дает хороший первый аргумент в пользу более продвинутых аргументов. Автор производного класса может не знать о базовом классе, возможно, намеревается создать новый метод, и мы не должны позволять пользователю переопределять по ошибке .
Хотя это обоснованно, существует ряд контраргументов, таких как:
- Автор производного класса обязан знать все о базовом классе! Они повторно используют этот код, и им следует тщательно изучить этот код, прежде чем его повторно использовать.
- В вашем конкретном сценарии виртуальный метод является абстрактным; было бы ошибкой не игнорировать его, и поэтому маловероятно, что автор будет создавать реализацию случайно.
Давайте тогда сделаем еще более продвинутый аргумент по этому вопросу. При каких обстоятельствах автора производного класса можно извинить за то, что он не знает, что делает базовый класс? Хорошо, рассмотрим этот сценарий:
- Автор базового класса составляет абстрактный базовый класс B.
- Автор производного класса в другой команде создает производный класс D с помощью метода M.
- Автор базового класса понимает, что командам, которые расширяют базовый класс B, всегда нужно будет предоставлять метод M, поэтому автор базового класса добавляет абстрактный метод M.
- Что происходит в случае перекомпиляции класса D?
Мы хотим, чтобы автор D был проинформирован о том, что что-то важное изменилось . Что изменилось, так это то, что M теперь является требованием и что их реализация должна быть перегружена. DM может понадобиться изменить свое поведение, как только мы узнаем, что его можно вызывать из базового класса. Правильно не молча сказать: «О, ДМ существует и расширяет БМ». Правильная вещь для компилятора - сбой , и скажите «эй, автор D, проверь свое предположение, которое больше не действует, и исправь свой код, если необходимо».
В вашем примере, предположим , что overrideбыло необязательно на , SayHelloпотому что это переопределение абстрактный метод. Есть две возможности: (1) автор кода намеревается переопределить абстрактный метод, или (2) переопределяющий метод переопределяется случайно, потому что кто-то еще изменил базовый класс, и код теперь каким-то тонким образом неверен. Мы не можем отличить эти возможности, если overrideэто необязательно .
Но если overrideэто требуется , то мы можем сказать друг от друга три сценария. Если в коде overrideесть возможная ошибка, то она отсутствует . Если он намеренно переопределение , то overrideесть присутствует . И если оно намеренно не переопределено, то newоно присутствует . Дизайн C # позволяет нам сделать эти тонкие различия.
Помните, что сообщение об ошибке компилятора требует чтения мыслей разработчика ; компилятор должен вывести из неправильного кода, какой правильный код, скорее всего, имел в виду автор , и выдать ошибку, указывающую на правильное направление. Чем больше подсказок мы можем заставить разработчика оставить в коде о том, о чем они думали, тем лучше работа компилятора по составлению отчетов об ошибках и, следовательно, тем быстрее вы сможете найти и исправить свои ошибки.
Но в целом, C # был разработан для мира, в котором меняется код . На самом деле очень много возможностей C #, которые кажутся «странными», потому что они информируют разработчика, когда предположение, которое раньше было действительным , стало недействительным, потому что изменился базовый класс. Этот класс ошибок называется «хрупкие сбои базового класса», и в C # есть ряд интересных мер для этого класса сбоев.