Override — Директива Delphi


Что такое смысл вновь и переопределения директивы в Delphi?

November 2020

13.3k раз

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

4 ответы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Что означает повторное введение и переопределение директив в Delphi?

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

4 ответа

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

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

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

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

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

В чем смысл директив reintroduce и overr >

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

4 ответов

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

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

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

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

язык объекта Delphi Pascal — не единственный язык, который распознает эту проблему. В C# требует использование директивы «override» по той же причине. Комитет по стандартам C++, наконец, признает эту проблему и изменяет язык для ее поддержки. что-то вроде того. В C++, если имя метода и список параметров соответствуют виртуальному предку, то это переопределение (даже если вы не говорите «виртуальный» на потомке!). Для предстоящего нового стандарта C++, если вы укажете «виртуальный» и подписи не совпадают, то это новый виртуальный метод, введенный в текущий класс. Если есть подпись совпадает с предком и писателем не намерены переопределить, затем ключевое слово » new » используется, чтобы сообщить компилятору, что это новая виртуальный для этого класса.

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

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

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

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

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

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

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

Илон Маск рекомендует:  Dos fn 48h распределить память (дать размер памяти)

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

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

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

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

Директива final для виртуальных методов. В чем ее смысл?

Суть вкратце: Если виртуальному методу написать final, то его нельзя будет наследовать:

Вроде понятно.
Внимание вопрос: А зачем так “городить огород”? Если не хочешь наследования, то просто не объявляй virtual . тогда никакие final и не нужны

Так зачем final ?
Пожалуйста, поделитесь идеями.

01.04.2020, 13:33

В чем смысл виртуальных функций?
Читаю книгу Джесс Либерти ‘С++ за 21 день’, не смотря на глупое название, книга очень грамотная и.

В чем принципиальное отличие виртуальных и невиртуальных методов в языке С++?
Добрый вечер! Не подскажите в чем принципиальное отличие виртуальных и невиртуальных методов в.

Вызов виртуальных методов
Добрый день! Не могу разобраться с примером из спецификации, объясните, пожалуйста, почему.

Наследование и переопределение виртуальных методов
Здравствуйте уважаемые программисты. Помогите разобраться с наследованием и переопределением.

Назначение виртуальных методов класса
Что-то никак не могу разобраться с виртуальными методами классов. В учебниках пишут, что они нужны.

01.04.2020, 15:17 2

нельзя будет override’нуть. Это не наследование, это переопределение.

01.04.2020, 16:09 3

как раз override — это наследование, переопределение — overload

Добавлено через 16 минут

01.04.2020, 17:06 4
01.04.2020, 17:06
01.04.2020, 17:52 5
01.04.2020, 17:58 6
02.04.2020, 08:05 7
02.04.2020, 08:57 8
02.04.2020, 09:08 9

Ландан из зэ кэпитал оф грит британ. Май нэйм из Васья, ай эм э пьюпал. Ай лив ин мухосранск.

02.04.2020, 09:44 10
02.04.2020, 23:41 11

а я себе запомнил эти слова как(чутку посарказмлю)
overload — переопределение/перезапись/переосмысливание чего-то, кончилась фантазия, а очень хочецця именнь так
override — добавка, к уже чему-то реализованному, то, что сказало virtual!
reintroduce — так как это слово не на О, но относится к тому же сериалу, то это нечто тоже, только всеже немножко не так
virtual — вторая половинка override(осталось уточнить кто из них М и кто Ж), virtual поди Ж, так как требует чтобы был override и подчинялся правилам
abstract — вышло помечтать, само делать не буду, пусть сделают за меня другие!

Что такое смысл вновь и переопределения директивы в Delphi?

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

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

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

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

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

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

Override — Директива Delphi

.
public
< Public declarations >
constructor Create(AOwner: TComponent); overload;
end;

Собственно вопрос. :o)

вопрос какой то странный, я его собственно и не вижу, в чем он?

overload — с помощью этой директивы ты можешь объявлять одноименные методы/процедуры с разным набором параметров

override — эта деректива перекрывает реализацию виртуального/динамического метода/конструктора/деструктора/(да и мало ли чего) родительского класса и обозначает, что у наследника она будет своя

и в чем»же твой вопрос после ликбеза?

1. Без разницы, если инстранцировать будешь как TForm1.Create.

2. Если инстранцировать будешь через Application.CreateForm(TForm1, Form1), тогда Override, в случае необходимости вызова твоего конструктора.

> вопрос какой то странный

Ну, почему не спросить stdcall или reitroduce, сабжевые слова просто похожи, отсюда и вопрос что ли .

Сори на писал только сейчас смог к ветке вернуться.

да, class
> Palladin © (12.05.08 16:11) [2]

> override — эта деректива перекрывает реализацию виртуального/динамического
> метода/конструктора/деструктора/(да и мало ли чего) родительского
> класса и обозначает, что у наследника она будет своя

Совершенно верно ! :o)

Только не найду ошибки, когда делаю override вылетает вот что:

Declaration of «Create» differs from previous declaration.

ЧЕЙ наследник этот твой класс ?

> User1 (12.05.08 18:57) [5]

Вы не поняли. Сергей спрашивал, от какого класса наследуется Ваш класс. Точнее, нужно знать объявление его конструктора — от этого зависит ответ на Ваш вопрос.

Дочернее окно. MDIChild


> Юрий Зотов © (12.05.08 19:13) [10]

Как раз при подстановке этого оператора и выскакивает:

Declaration of «Create» differs from previous declaration.

Прошу прощения ребята !
Нашел ошибку, а скорее недоучет.

Дело в том, я забыл обозначить, что передается еще один параметр ARec :
constructor Create(AOwner: TComponent; ARec: THandBook); overload ; а в этом случае поможет только overload .

Потому и соответствующее сообщение :
Declaration of «Create» differs from previous declaration.

overload — полиморфизм, для разных параметров в методе.
override — переопределяем сам метод.
reintroduce — просто убирает предупреждение компилятора.


> Declaration of «Create» differs from previous declaration.

Ессно ты же параметры у Create меняешь — этого лучше не делать. inherited конструктор вызвать не забудь только.


> inherited конструктор вызвать не забудь только.

C этим норм.

А вообще суечусь для справочника.

Тип такого чтот:

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, ExtCtrls, ComCtrls, ToolWin, DBCtrls, Grids, DBGridEh,
DB, StdCtrls;

TShowHandBook = (shbUnknown, shbRequisite, shbEmployee, shbJobTitle, shbUser, shbRole,
shbLog, shbPlace, shbPoint, shbTpPoint, shbStreet, shbTpStreet, shbHome,
shbTpHome, shbPost, shbManagement, shbProperty, shbOtherRem, shbEntrance,
shbApartment, shbRoom, shbTpRoom);

PHandBook = ^THandBook;
THandBook = packed record
ShowType: TShowHandBook;
case Integer of
0: (
GoToIndex: Integer);
end;

TfHandBook = class(TForm)
pnl: TPanel;
sBtnClose: TSpeedButton;
sBtnPrint: TSpeedButton;
sBtnHelp: TSpeedButton;
tb: TToolBar;
sbInfo: TStatusBar;
sb: TStatusBar;
nv: TDBNavigator;
tSprt1: TToolButton;
tBtnFilter: TToolButton;
grd: TDBGridEh;
ds: TDataSource;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormDeactivate(Sender: TObject);
procedure FormHide(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
< Private declarations >
FRec: THandBook;
public
< Public declarations >
constructor Create(AOwner: TComponent; ARec: THandBook); overload;
end;

function CreateHandBook(AOwner: TComponent; ARec: THandBook): Boolean;

resourcestring
SUnknown = «Íåèçâåñòíûé ñïðàâî÷íèê»;
SRequisite = «Ñïðàâî÷íèê ðåêâèçèòû ïðåäïðèÿòèÿ»;
SEmployee = «»;
SJobTitle = «»;
SUser = «»;
SRole = «»;
SLog = «»;
SPlace = «»;
SPoint = «»;
STpPoint = «»;
SStreet = «»;
STpStreet = «»;
SHome = «»;
STpHome = «»;
SPost = «»;
SManagement = «»;
SProperty = «»;
SOtherRem = «»;
SEntrance = «»;
SApartment = «»;
SRoom = «»;
STpRoom = «»;

var
fHandBook: TfHandBook;

function CreateHandBook(AOwner: TComponent; ARec: THandBook): Boolean;
begin
if Assigned(fHandBook) then
if (fHandBook.FRec.ShowType <> ARec.ShowType) or
(fHandBook.FRec.GoToIndex <> ARec.GoToIndex) then
fHandBook.Free
else
if not (fHandBook.WindowState in [wsNormal, wsMaximized]) then
fHandBook.WindowState := wsNormal
else
fHandBook.Show;

Result := True;
try
if not Assigned(fHandBook) then
fHandBook := TfHandBook.Create(AOwner, ARec);
except
Result := False;
fHandBook.Free;
fHandBook := nil;
end;
end;

constructor TfHandBook.Create(AOwner: TComponent; ARec: THandBook);
begin
inherited Create(AOwner);
FRec := ARec;
case FRec.ShowType of
shbUnknown:
begin
Close;
end;
shbRequisite:
begin
Caption := SRequisite;
ds.DataSet := dm.qRequisite;
end;
else
begin
//Íåèçâåñòíûé âèä âûçûâàåìîãî ñïðàâî÷íèêè.
end;
end;
end;

procedure TfHandBook.FormCreate(Sender: TObject);
begin
if OpenDataSet(ds.DataSet) then
begin
//
end
else
begin
//
end;
end;

procedure TfHandBook.FormShow(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormPaint(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormActivate(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormResize(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
begin
//
end;

procedure TfHandBook.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//
end;

procedure TfHandBook.FormDeactivate(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormHide(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormDestroy(Sender: TObject);
begin
//
end;

Чему вас только Пачеко учил.


> Игорь Шевченко © (12.05.08 20:32) [16]

И чему же. ? :o)


begin
inherited Create(AOwner);
FRec := ARec;
case FRec.ShowType of
shbUnknown:
begin
Close;
end;
shbRequisite:
begin
Caption := SRequisite;
ds.DataSet := dm.qRequisite;
end;
else
begin
//Íåèçâåñòíûé âèä âûçûâàåìîãî ñïðàâî÷íèêè.
end;
end;
end;

Какой Close в OnCreate ? И в OnShow тоже нельзя. Проверяй перед созданием формы, а не в ней. Или Error взводи.


> tesseract © (12.05.08 20:36) [18]

Честно, налобал даже не проверял. :o) просто «мысль гения» пришла, а сому «последовательность» shbUnknown даже ниразу не вызывал. :o)))

> tesseract © (12.05.08 20:26) [14]

Overload — НЕ полиморфизм (а перегрузка). А вот override — это как раз полиморфизм и есть.


> налобал даже не проверял

Да уж..
Тело ф-ции CreateHandBook — шедевр, достойный истинного «лобуха»)


> Юрий Зотов © (12.05.08 20:44) [20]

Не предал значения. Совершенно верно !


> Overload — НЕ полиморфизм (а перегрузка).

В общем-то да. overload не перекрывает сам метод. Определение «полиморфизма» само по себе туманновато.

Кратко смысл полиморфизма можно выразить фразой: «Один интерфейс, множество методов».

Полиморфизм — один из трех важнейших механизмов объектно-ориентированного программирования (наряду с инкапсуляцией и наследованием).

Полиморфизм позволяет писать более абстрактные программы и повысить коэффициент повторного использования кода. Общие свойства объектов объединяются в систему, которую могут называть по-разному — интерфейс, класс. Общность имеет внешнее и внутреннее выражение. Внешне общность проявляется как одинаковый набор методов с одинаковыми именами и сигнатурами (типами аргументов и результатов). Внутренняя общность есть одинаковая функциональность методов. Её можно описать интуитивно или выразить в виде строгих законов, правил, которым должны подчиняться методы. Возможность приписывать разную функциональность одному методу (функции, операции) называется перегрузкой метода (функций, операций).

> tesseract © (12.05.08 20:53) [23]

> Определение «полиморфизма» само по себе туманновато.

По смыслу — разное поведение одного и того же метода в зависимости от класса. По сути — всего лишь косвенная адресация. Ничего туманного.


> По смыслу — разное поведение одного и того же метода в зависимости
> от класса.

Определение туманно. Как работает, ясно конечно.

Ну хватит оправдываться. Все ошибаются.
:)


> tesseract © (12.05.08 21:33) [26]
>
>
> > По смыслу — разное поведение одного и того же метода в
> зависимости
> > от класса.
>
>
> Определение туманно. Как работает, ясно конечно.

Очень напомнило «Координаты чудес» Шэкли. :)

function CreateHandBook.
begin
if Assigned(fHandBook) then
..
fHandBook.Free //разрушение объекта, в fHandBook остается мусор (1)
..
try
if not Assigned(fHandBook) then // в случае (1) уловие будет ложным
fHandBook := TfHandBook.Create(AOwner, ARec); //и эта строчка никогда не будет выполнена (2)
except
fHandBook.Free; // в случае исключения при выполнении (2) разрушение заведомо несозданного объекта лишено всякого смысла
fHandBook := nil; // равно как лишена смысла и эта строчка
end;
end;


> Сергей М. © (13.05.08 08:28) [30]

function CreateHandBook(AOwner: TComponent; ARec: THandBook): Boolean;
begin
if Assigned(fHandBook) then
if (fHandBook.FRec.ShowType <> ARec.ShowType) or
(fHandBook.FRec.GoToIndex <> ARec.GoToIndex) then
begin
fHandBook.Free;
fHandBook := nil;
end
else
if not (fHandBook.WindowState in [wsNormal, wsMaximized]) then
fHandBook.WindowState := wsNormal
else
fHandBook.Show;

Result := True;
try
if not Assigned(fHandBook) then
fHandBook := TfHandBook.Create(AOwner, ARec);
except
Result := False;
end;
end;

function CreateHandBook(AOwner: TComponent; ARec: THandBook): Boolean;
begin
Result := True;
if Assigned(fHandBook) then
if (fHandBook.FRec.ShowType <> ARec.ShowType) or
(fHandBook.FRec.GoToIndex <> ARec.GoToIndex) then
FreeAndNil(fHandBook)
else
if not (fHandBook.WindowState in [wsNormal, wsMaximized]) then
fHandBook.WindowState := wsNormal
else
fHandBook.Show;

if not Assigned(fHandBook) then
try
fHandBook := TfHandBook.Create(AOwner, ARec);
except
Result := False;
end;
end;

Кто-то писал справочники такого вида, как я пытаюсь написать ?
Если да, то кто, что посоветует по этому поводу.


> Сергей М. © (13.05.08 11:00) [35]

unit uHandBook;

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, ExtCtrls, ComCtrls, ToolWin, DBCtrls, Grids, DBGridEh,
DB, StdCtrls;

TShowHandBook = (shbUnknown, shbRequisite, shbEmployee, shbJobTitle, shbUser, shbRole,
shbLog, shbPlace, shbPoint, shbTpPoint, shbStreet, shbTpStreet, shbHome,
shbTpHome, shbPost, shbManagement, shbProperty, shbOtherRem, shbEntrance,
shbApartment, shbRoom, shbTpRoom);

PHandBook = ^THandBook;
THandBook = packed record
ShowType: TShowHandBook;
case Integer of
0: (
GoToIndex: Integer);
end;

TfHandBook = class(TForm)
pnl: TPanel;
sBtnClose: TSpeedButton;
sBtnPrint: TSpeedButton;
sBtnHelp: TSpeedButton;
tb: TToolBar;
sbInfo: TStatusBar;
sb: TStatusBar;
nv: TDBNavigator;
tSprt1: TToolButton;
tBtnFilter: TToolButton;
grd: TDBGridEh;
ds: TDataSource;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormDeactivate(Sender: TObject);
procedure FormHide(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
< Private declarations >
FRec: THandBook;
public
< Public declarations >
constructor Create(AOwner: TComponent; ARec: THandBook); overload;
end;

function CreateHandBook(AOwner: TComponent; ARec: THandBook): Boolean;

resourcestring
SUnknown = «Íåèçâåñòíûé ñïðàâî÷íèê»;
SRequisite = «Ñïðàâî÷íèê ðåêâèçèòû ïðåäïðèÿòèÿ»;
SEmployee = «»;
SJobTitle = «»;
SUser = «»;
SRole = «»;
SLog = «»;
SPlace = «»;
SPoint = «»;
STpPoint = «»;
SStreet = «»;
STpStreet = «»;
SHome = «»;
STpHome = «»;
SPost = «»;
SManagement = «»;
SProperty = «»;
SOtherRem = «»;
SEntrance = «»;
SApartment = «»;
SRoom = «»;
STpRoom = «»;

var
fHandBook: TfHandBook;

function CreateHandBook(AOwner: TComponent; ARec: THandBook): Boolean;
begin
if Assigned(fHandBook) then
if (fHandBook.FRec.ShowType <> ARec.ShowType) or
(fHandBook.FRec.GoToIndex <> ARec.GoToIndex) then
fHandBook.Free
else
if not (fHandBook.WindowState in [wsNormal, wsMaximized]) then
fHandBook.WindowState := wsNormal
else
fHandBook.Show;

Result := True;
try
if not Assigned(fHandBook) then
fHandBook := TfHandBook.Create(AOwner, ARec);
except
Result := False;
fHandBook.Free;
fHandBook := nil;
end;
end;

constructor TfHandBook.Create(AOwner: TComponent; ARec: THandBook);
begin
inherited Create(AOwner);
FRec := ARec;
case FRec.ShowType of
shbUnknown:
begin
Close;
end;
shbRequisite:
begin
Caption := SRequisite;
ds.DataSet := dm.qRequisite;
end;
else
begin
//Íåèçâåñòíûé âèä âûçûâàåìîãî ñïðàâî÷íèêè.
end;
end;
end;

procedure TfHandBook.FormCreate(Sender: TObject);
begin
if OpenDataSet(ds.DataSet) then
begin
//
end
else
begin
//
end;
end;

procedure TfHandBook.FormShow(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormPaint(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormActivate(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormResize(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
begin
//
end;

procedure TfHandBook.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//
end;

procedure TfHandBook.FormDeactivate(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormHide(Sender: TObject);
begin
//
end;

procedure TfHandBook.FormDestroy(Sender: TObject);
begin
//
end;

Все выбросить на помойку клавишей Shift+Delete

Читать Тейксейру с Пачеко

Это не справочник, это просто лобуховая декларация и реализация некоего класса формы)


> Сергей М. © (13.05.08 11:20) [38]

А что же догда понимать под справочником программы ?

Тогда объясните как реализовать «гибкий справочник» для работы с некоторыми таблицами в БД .


> что же догда понимать под справочником программы ?

Это тебя надо спросить, что ты под этим понимаешь)


> как реализовать «гибкий справочник»

Delphi: объясните своими словами virtual, abstract и override

Не вдаваясь в тонкости, можно сказать, что методы классов могут быть статическими и виртуальными. Статический метод не переопределяется. Поэтому, если вы породили потомка от некоторого класса, то он унаследует статический метод родителя и при его вызове будет исполнен код, реализованный в родительском методе. Для того, чтобы в потомке можно было изменить поведение метода, его объявляют со служебным словом virtual; При этом название метода и список параметров должны в точности соответствовать названию и списку параметров родителя.

При переопределении родительcких методов используется директива override;

Methods (Delphi)

Contents

A method is a procedure or function associated with a >SomeObject.Free calls the Free method in SomeObject .

This topic covers the following material:

  • Method declarations and implementation
  • Method binding
  • Overloading methods
  • Constructors and destructors
  • Message methods

About Methods

Within a >TMyClass includes a method called DoSomething :

A defining declaration for DoSomething must occur later in the module:

While a class can be declared in either the interface or the implementation section of a unit, defining declarations for a class methods must be in the implementation section.

In the heading of a defining declaration, the method name is always qualified with the name of the class to which it belongs. The heading can repeat the parameter list from the class declaration; if it does, the order, type, and names of the parameters must match exactly, and if the method is a function, the return value must match as well.

Method declarations can include special directives that are not used with other functions or procedures. Directives should appear in the class declaration only, not in the defining declaration, and should always be listed in the following order:

  • binding is virtual, dynamic, or override;
  • calling convention is register, pascal, cdecl, stdcall, or safecall;
  • warning is platform, deprecated, or library. For more information about these warning (hinting) directives, see Hinting Directives.

All Delphi directives are listed in Directives.

Inherited

The reserved word inherited plays a special role in implementing polymorphic behavior. It can occur in method definitions, with or without an identifier after it.

If inherited is followed by the name of a member, it represents a normal method call or reference to a property or field, except that the search for the referenced member begins with the immediate ancestor of the enclosing method’s class. For example, when:

occurs in the definition of a method, it calls the inherited Create .

When inherited has no identifier after it, it refers to the inherited method with the same name as the enclosing method or, if the enclosing method is a message handler, to the inherited message handler for the same message. In this case, inherited takes no explicit parameters, but passes to the inherited method the same parameters with which the enclosing method was called. For example:

occurs frequently in the implementation of constructors. It calls the inherited constructor with the same parameters that were passed to the descendant.

Within the implementation of a method, the >Add method in the Classes unit:

The Add method calls the Create method in the >FItemClass field, which is always a TCollectionItem descendant. TCollectionItem.Create takes a single parameter of type TCollection, so Add passes it the TCollection instance object where Add is called. This is illustrated in the following code:

Self is useful for a variety of reasons. For example, a member >Self.Identifier .

For information about Self in class methods, see «Class Operators» in Class References.

Method Binding

Method bindings can be static (the default), virtual, or dynamic. Virtual and dynamic methods can be overridden, and they can be abstract. These designations come into play when a variable of one class type holds a value of a descendent class type. They determine which implementation is activated when a method is called.

Static Methods

Methods are by default static. When a static method is called, the declared (compile-time) type of the >Draw methods are static:

Given these declarations, the following code illustrates the effect of calling a static method. In the second call to Figure.Draw , the Figure variable references an object of >TRectangle , but the call invokes the implementation of Draw in TFigure , because the declared type of the Figure variable is TFigure :

Virtual and Dynamic Methods

To make a method virtual or dynamic, include the virtual or dynamic directive in its declaration. Virtual and dynamic methods, unlike static methods, can be overridden in descendent classes. When an overridden method is called, the actual (run-time) type of the class or object used in the method call—not the declared type of the variable—determines which implementation to activate.

To override a method, redeclare it with the override directive. An override declaration must match the ancestor declaration in the order and type of its parameters and in its result type (if any).

In the following example, the Draw method declared in TFigure is overridden in two descendent classes:

Given these declarations, the following code illustrates the effect of calling a virtual method through a variable whose actual type varies at run time:

Only virtual and dynamic methods can be overridden. All methods, however, can be overloaded; see Overloading methods.

Final Methods

The Delphi compiler also supports the concept of final virtual and dynamic methods. Declarations of final methods have the form:

Here the virtual|dynamic syntax (two keywords and the | pipe between them) is used to specify that one and only one of the virtual or dynamic keywords should be used. Meaningful is only the virtual or dynamic keyword; the pipe symbol itself should be deleted.

When the keyword final is applied to a virtual or dynamic method, no descendent class can override that method. Use of the final keyword is an important design decision that can help document how the class is intended to be used. It can also give the compiler hints that allow it to optimize the code it produces.

Note: The virtual or dynamic keywords must be written before the final keyword.

Virtual versus Dynamic

In Delphi for Win32, virtual and dynamic methods are semantically equivalent. However, they differ in the implementation of method-call dispatching at run time: virtual methods optimize for speed, while dynamic methods optimize for code size.

In general, virtual methods are the most efficient way to implement polymorphic behavior. Dynamic methods are useful when a base class declares many overridable methods that are inherited by many descendent classes in an application, but only occasionally overridden.

Note: Only use dynamic methods if there is a clear, observable benefit. Generally, use virtual methods.

Overriding versus Hiding

If a method declaration specifies the same method identifier and parameter signature as an inherited method, but does not include override, the new declaration merely hides the inherited one without overriding it. Both methods exist in the descendent class, where the method name is statically bound. For example:

Reintroduce

The reintroduce directive suppresses compiler warnings about hiding previously declared virtual methods. For example:

Use reintroduce when you want to hide an inherited virtual method with a new one.

Abstract Methods

An abstract method is a virtual or dynamic method that has no implementation in the class where it is declared. Its implementation is deferred to a descendent class. Abstract methods must be declared with the directive abstract after virtual or dynamic. For example:

You can call an abstract method only in a class or instance of a class in which the method has been overridden.

Class Methods

Most methods are called instance methods, because they operate on an individual instance of an object. A class method is a method (other than a constructor) that operates on classes instead of objects. There are two types of class methods: ordinary class methods and class static methods.

Ordinary Class Methods

The definition of a class method must begin with the reserved word class. For example:

The defining declaration of a class method must also begin with class. For example:

In the defining declaration of a >C , then Self is of the type >C . Thus you cannot use Self to access instance fields, instance properties, and normal (object) methods. You can use Self to call constructors and other class methods, or to access class properties and class fields.

A class method can be called through a class reference or an object reference. When it is called through an object reference, the class of the object becomes the value of Self.

Class Static Methods

Like class methods, class static methods can be accessed without an object reference. Unlike ordinary class methods, class static methods have no Self parameter at all. They also cannot access any instance members. (They still have access to class fields, class properties, and class methods.) Also unlike class methods, class static methods cannot be declared virtual.

Methods are made class static by appending the word static to their declaration, for example:

Like a class method, you can call a class static method through the class type (for example, without having an object reference), such as:

Overloading Methods

A method can be redeclared using the overload directive. In this case, if the redeclared method has a different parameter signature from its ancestor, it overloads the inherited method without hiding it. Calling the method in a descendent class activates whichever implementation matches the parameters in the call.

If you overload a virtual method, use the reintroduce directive when you redeclare it in descendent classes. For example:

Within a class, you cannot publish multiple overloaded methods with the same name. Maintenance of run time type information requires a unique name for each published member:

Methods that serve as property read or write specifiers cannot be overloaded.

The implementation of an overloaded method must repeat the parameter list from the class declaration. For more information about overloading, see Overloading Procedures and Functions in Procedures and Functions (Delphi).

Constructors

A constructor is a special method that creates and initializes instance objects. The declaration of a constructor looks like a procedure declaration, but it begins with the word constructor. Examples:

Constructors must use the default register calling convention. Although the declaration specifies no return value, a constructor returns a reference to the object it creates or is called in.

To create an object, call the constructor method on a class type. For example:

This allocates storage for the new object, sets the values of all ordinal fields to zero, assigns nil to all pointer and class-type fields, and makes all string fields empty. Other actions specified in the constructor implementation are performed next; typically, objects are initialized based on values passed as parameters to the constructor. Finally, the constructor returns a reference to the newly allocated and initialized object. The type of the returned value is the same as the class type specified in the constructor call.

If an exception is raised during the execution of a constructor that was invoked on a >Destroy destructor is automatically called to destroy the unfinished object.

When a constructor is called using an object reference (rather than a class reference), it does not create an object. Instead, the constructor operates on the specified object, executing only the statements in the constructor’s implementation, and then returns a reference to the object. A constructor is typically invoked on an object reference in conjunction with the reserved word inherited to execute an inherited constructor.

Here is an example of a class type and its constructor:

The first action of a constructor is usually to call an inherited constructor to initialize the object’s inherited fields. The constructor then initializes the fields introduced in the descendent class. Because a constructor always clears the storage it allocates for a new object, all fields start with a value of zero (ordinal types), nil (pointer and class types), empty (string types), or Unassigned (variants). Hence there is no need to initialize fields in a constructor’s implementation except to nonzero or nonempty values.

When invoked through a class-type identifier, a constructor declared virtual is equivalent to a static constructor. When combined with class-reference types, however, virtual constructors allow polymorphic construction of objects—that is, construction of objects whose types are not known at compile time. (See Class References.)

Destructors

A destructor is a special method that destroys the object where it is called and deallocates its memory. The declaration of a destructor looks like a procedure declaration, but it begins with the word destructor. Example:

Destructors on Win32 must use the default register calling convention. Although a >Destroy method and declare no other destructors.

To call a destructor, you must reference an instance object. For example:

When a destructor is called, actions specified in the destructor implementation are performed first. Typically, these consist of destroying any embedded objects and freeing resources that were allocated by the object. Then the storage that was allocated for the object is disposed of.

Here is an example of a destructor implementation:

The last action in a destructor implementation is typically to call the inherited destructor to destroy the inherited fields of the object.

When an exception is raised during the creation of an object, Destroy is automatically called to dispose of the unfinished object. This means that Destroy must be prepared to dispose of partially constructed objects. Because a constructor sets the fields of a new object to zero or empty values before performing other actions, >Destroy offers a convenient way to check for nil values before destroying an object.

Class Constructors

A class constructor is a special class method that is not accessible to developers. Calls to class constructors are inserted automatically by the compiler into the initialization section of the unit where the class is defined. Normally, class constructors are used to initialize the static fields of the class or to perform a type of initialization, which is required before the class or any class instance can function properly. Even though the same result can be obtained by placing class initialization code into the initialization section, class constructors have the benefit of helping the compiler decide which classes should be included into the final binary file and which should be removed from it.

The next example shows the usual way of initializing class fields:

This method has a big disadvantage: even though an application can include the unit in which TBox is declared, it may never actually use the TBox class. In the current example, the TBox class is included into the resulting binary, because it is referenced in the initialization section. To alleviate this problem, consider using class constructors:

In this case, the compiler checks whether TBox is actually used anywhere in the application, and if it is used, a call to the class constructor is added automatically to the initialization section of the unit.

Note: Even though the compiler takes care of ordering the initialization of classes, in some complex scenarios, ordering may become random. This happens when the class constructor of a class depends on the state of another class that, in turn, depends on the first class.

Note: The class constructor for a generic class or record may execute multiple times. The exact number of times the class constructor is executed in this case depends on the number of specialized versions of the generic type. For example, the class constructor for a specialized TList class may execute multiple times in the same application.

Class Destructors

Class destructors are the opposite of class constructors in that they perform the finalization of the class. Class destructors come with the same advantages as class constructors, except for finalization purposes.

The following example builds on the example shown in class constructors and introduces the finalization routine:

Note: The class destructor for a generic class or record may execute multiple times. The exact number of times the class destructor is executed in this case depends on the number of specialized versions of the generic type. For example, the class destructor for a specialized TList class may execute multiple times in the same application.

Message Methods

Message methods implement responses to dynamically dispatched messages. The message method syntax is supported on all platforms. VCL uses message methods to respond to Windows messages.

A message method is created by including the message directive in a method declaration, followed by an integer constant from 1 through 49151 that specifies the message > For message methods in VCL controls, the integer constant can be one of the Win32 message >Messages unit. A message method must be a procedure that takes a single var parameter.

A message method does not have to include the override directive to override an inherited message method. In fact, it does not have to specify the same method name or parameter type as the method it overrides. The message ID alone determines to which message the method responds and whether it is an override.

Implementing Message Methods

The implementation of a message method can call the inherited message method, as in the following example:

The inherited statement searches backward through the >DefaultHandler method originally defined in TObject.

The implementation of DefaultHandler in TObject simply returns without performing any actions. By overr >DefaultHandler , a >DefaultHandler method for controls calls the Win32 API DefWindowProc .

Message Dispatching

Message handlers are seldom called directly. Instead, messages are dispatched to an object using the Dispatch method inherited from TObject:

The Message parameter passed to Dispatch must be a record whose first entry is a field of type Word containing a message ID.

Dispatch searches backward through the >Dispatch calls DefaultHandler .

Override — Директива Delphi

Кто-нибудь знает, в чем разница между перекрытием (OVERRIDING) виртуального метода и заменой (REPLACING) его? Я немного запутался.

Допустим у вас есть класс:

и его наследник:

К примеру, TMyObject имеет метод Wiggle:

а TOverrideObject перекрывает Wiggle:

и, естественно, вы реализовали оба метода.

Теперь вы создаете TList, содержащий целую кучу MyObjects и OverrideObjects в свойстве TList.Items[n]. Свойство Items является указателем, поэтому для вызова метода Wiggle вам достаточно вызвать необходимый элемент списка. Например так:

но возможности полиморфизма и директива override позволяют вам сделать так:

Ваше приложение посмотрит на экземпляр специфического объекта, ссылка на который содержится в Items[1] и скажет: «Да, это — TMyObject, но, точнее говоря, это TOverrideObject; но поскольку метод Wiggle является виртуальным методом и TOverrideObject переопределил метод Wiggle, я собираюсь выполнить метод TOverrideObject.Wiggle, а не метод TMyObject.Wiggle.»

Теперь представьте себе, что при декларации метода вы пропустили директиву override, попробуйте это выполнить теперь:

Приложение и в этом случае должно «видеть» данный метод, даже если Items[1] — TOverrideObject; но у него отсутствует перекрытая версия метода Wiggle, поэтому приложение выполнит TMyObject.Wiggle, а не TOverrideObject.Wiggle (поведение, которое вы можете как хотеть, так и избегать).

Так, перекрытый метод функционально может отличаться от декларированного метода, содержащего директиву virtual (или dynamic) в базовом классе, и объявленный с директивой override в классе-наследнике. Для замены метода необходимо объявить его в классе-наследнике без директивы override. Перекрытые методы могут выполняться даже тогда, когда специфический экземпляр класса-предка является точной копией базового класса. «Замененные» методы могут выполняться только тогда, когда специфический экземпляр является «слепком» только этого класса.

Что такое смысл вновь и переопределения директивы в Delphi?

November 2020

13.3k раз

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

4 ответы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Илон Маск рекомендует:  Внешняя рамка элемента. Свойство outline
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL