Подтвердить что ты не робот

В чем смысл реинтродукции и переопределения директив в Delphi?

В чем разница между директивами override и reintroduce? И когда я не должен использовать ключевое слово inherited в переопределенных методах?

4b9b3361

Ответ 1

Ссылка на ответ Джима, который был отличным BTW, описывает только когда и где использовать директивы. Другая часть ответа - зачем они нужны? Многие языки прекрасно ладят без них, верно? При разработке аспектов языка Delphi Object Pascal, ООП (объектно-ориентированное программирование) уже несколько лет находится в русле. За это время было замечено, что использование многих языков, принявших эти концепции (Turbo Pascal, С++ и т.д.) Для разработки рамок приложений, пострадавших от того, что я назвал проблемой "версии 2".

Предположим, что вы разработали потрясающую структуру с использованием языка X и выпустили ее в качестве версии 1. Ваши пользователи обольстили ее вообще, и она стала широко использоваться. Попытайтесь с успехом, вы решите выпустить версию 2 с еще большей простотой. Вы специально удостоверились, что он полностью совместим с обратной связью. Внезапно вы начали рассказывать о странном поведении. Их собственные виртуальные методы вызывались в странные времена. Многие сообщили, что их старый код не будет компилироваться с новой версией. Странно. Все те же объекты, методы и функциональность все еще оставались. Все, что вы сделали, это добавить несколько виртуальных методов к некоторым базовым классам, некоторым новым типам объектов и некоторым новым дополнительным функциям. Что случилось?

Завершение и повторное введение директив служат для устранения этой проблемы, требуя, чтобы для фактического переопределения виртуального метода вместо директивы virtual вместо директивы переопределения. Если вам представится ваш собственный виртуальный метод, который имеет то же имя, что и один из ваших виртуальных методов ваших предков, компилятор теперь предупреждает вас, но все равно будет делать все правильно. В этом случае использование повторного ввода не только подавляет это предупреждение, но также служит для документирования в источнике, который вы намеревались сделать.

Без переопределения и повторного введения директив вы не сможете постоянно развивать свою структуру, не опасаясь сломать всех своих пользователей. И если ваши пользователи должны были вносить огромные изменения каждый раз, когда выпускается новая версия, тогда им будет не хватать новой версии. Наконец, использование "переопределения" также позволяет дизайнеру фреймворка изменять тип виртуального в предках без нарушения кода пользователя. Например, в Delphi многие методы отмечены как "динамические", которые представляют собой метод поиска методов поиска на основе таблицы полиморфизма. Он работает не так быстро, как обычный виртуальный, поэтому он обычно используется для методов, которые редко переопределяются и/или являются ответами на действия пользователя, когда лишние служебные данные никогда не замечаются. Предположим, что в V1 рамки метод был отмечен как "динамический", но на практике он оказался переопределенным и назывался больше, чем вы предполагали. В V2 вы можете изменить его на "виртуальный" , не опасаясь сломаться код пользователя.

Язык Delphi Object Pascal не является единственным языком для распознавания этой проблемы. С# требует использования директивы "переопределить" по той же причине. Комитет по стандартам С++, наконец, распознает проблему и модифицирует язык для ее поддержки... своего рода. В С++, если имя метода и список параметров соответствуют виртуальному предку, то это переопределение (даже если вы не говорите "виртуальный" на потомке!). Для нового нового стандарта С++, если вы укажете "виртуальный" , а подписи не совпадают, это новый виртуальный метод, введенный в текущий класс. Если есть соответствие подписи с предком, и автор не намеревался переопределить, тогда ключевое слово "новое" используется, чтобы сообщить компилятору, что это новый виртуальный для этого класса.

Ответ 2

Директива переопределить используется для переопределения виртуальных методов в унаследованных классах.

Директива reintroduce используется для объявления метода с тем же именем, что и в суперклассе, но с разными параметрами.

Ответ 3

И когда я не должен использовать унаследованное ключевое слово в переопределенных методах?

В принципе, ответ заключается в том, что вы не хотите, чтобы унаследованный метод выполнялся. Будьте осторожны, поскольку, поскольку не позволяет унаследованному методу запускать, может нарушить функциональность унаследованного объекта нежелательным образом, поэтому убедитесь, что вы не вводите какие-либо непреднамеренные побочные эффекты.

В качестве примера предположим, что вы хотите полностью переопределить унаследованную функцию, называемую ApplyDiscount, но кто-то жестко закодировал процент скидок в классе предков. Если вы вызываете унаследованный ApplyDiscount, он переопределит ваш код или вычислит значение, которое вы затем переопределите; в этом случае вы можете просто не называть унаследованные и применять скидку самостоятельно.

(Это надуманный пример, поэтому, если кто-то может подумать о лучшем, добавьте его.)

Ответ 4

Есть много обстоятельств, когда вы не хотите вызывать унаследованные в переопределенном методе.

В некоторых библиотеках, которые я использую, базовый метод выдает ошибку (ENotImplimented или подобное). Очевидно, что в этом случае вы не хотите вызывать унаследованным, иначе ваш код также выдаст ошибку.

Некоторые из моих классов имеют реализацию по умолчанию, которая работает в большинстве случаев. Метод переопределяется только для замены значения по умолчанию, и нет необходимости вызывать значение по умолчанию.

Например, функция GST (= налог с продаж) моего базового финансового объекта возвращает 12,5% от суммы ExGst, а IncGst возвращает ExGst + GST.

В моих объектах Income Compensation GST всегда возвращает 0, поэтому нет необходимости вызывать унаследованную функцию.