Ответ 1
Ссылка на ответ Джима, который был отличным BTW, описывает только когда и где использовать директивы. Другая часть ответа - зачем они нужны? Многие языки прекрасно ладят без них, верно? При разработке аспектов языка Delphi Object Pascal, ООП (объектно-ориентированное программирование) уже несколько лет находится в русле. За это время было замечено, что использование многих языков, принявших эти концепции (Turbo Pascal, С++ и т.д.) Для разработки рамок приложений, пострадавших от того, что я назвал проблемой "версии 2".
Предположим, что вы разработали потрясающую структуру с использованием языка X и выпустили ее в качестве версии 1. Ваши пользователи обольстили ее вообще, и она стала широко использоваться. Попытайтесь с успехом, вы решите выпустить версию 2 с еще большей простотой. Вы специально удостоверились, что он полностью совместим с обратной связью. Внезапно вы начали рассказывать о странном поведении. Их собственные виртуальные методы вызывались в странные времена. Многие сообщили, что их старый код не будет компилироваться с новой версией. Странно. Все те же объекты, методы и функциональность все еще оставались. Все, что вы сделали, это добавить несколько виртуальных методов к некоторым базовым классам, некоторым новым типам объектов и некоторым новым дополнительным функциям. Что случилось?
Завершение и повторное введение директив служат для устранения этой проблемы, требуя, чтобы для фактического переопределения виртуального метода вместо директивы virtual вместо директивы переопределения. Если вам представится ваш собственный виртуальный метод, который имеет то же имя, что и один из ваших виртуальных методов ваших предков, компилятор теперь предупреждает вас, но все равно будет делать все правильно. В этом случае использование повторного ввода не только подавляет это предупреждение, но также служит для документирования в источнике, который вы намеревались сделать.
Без переопределения и повторного введения директив вы не сможете постоянно развивать свою структуру, не опасаясь сломать всех своих пользователей. И если ваши пользователи должны были вносить огромные изменения каждый раз, когда выпускается новая версия, тогда им будет не хватать новой версии. Наконец, использование "переопределения" также позволяет дизайнеру фреймворка изменять тип виртуального в предках без нарушения кода пользователя. Например, в Delphi многие методы отмечены как "динамические", которые представляют собой метод поиска методов поиска на основе таблицы полиморфизма. Он работает не так быстро, как обычный виртуальный, поэтому он обычно используется для методов, которые редко переопределяются и/или являются ответами на действия пользователя, когда лишние служебные данные никогда не замечаются. Предположим, что в V1 рамки метод был отмечен как "динамический", но на практике он оказался переопределенным и назывался больше, чем вы предполагали. В V2 вы можете изменить его на "виртуальный" , не опасаясь сломаться код пользователя.
Язык Delphi Object Pascal не является единственным языком для распознавания этой проблемы. С# требует использования директивы "переопределить" по той же причине. Комитет по стандартам С++, наконец, распознает проблему и модифицирует язык для ее поддержки... своего рода. В С++, если имя метода и список параметров соответствуют виртуальному предку, то это переопределение (даже если вы не говорите "виртуальный" на потомке!). Для нового нового стандарта С++, если вы укажете "виртуальный" , а подписи не совпадают, это новый виртуальный метод, введенный в текущий класс. Если есть соответствие подписи с предком, и автор не намеревался переопределить, тогда ключевое слово "новое" используется, чтобы сообщить компилятору, что это новый виртуальный для этого класса.