Проблема с ООП, Баг с наследованием. |
1. Заголовок или название темы должно быть информативным !
2. Все тексты фрагментов программ должны помещаться в теги [code] ... [/code] или [code=pas] ... [/code].
3. Прежде чем задавать вопрос, см. "FAQ" и используйте ПОИСК !
4. НЕ используйте форум для личного общения!
5. Самое главное - это раздел теоретический, т.е. никаких задач и программ (за исключением небольших фрагментов) - для этого есть отдельный раздел!
Проблема с ООП, Баг с наследованием. |
LHx |
Сообщение
#1
|
Новичок Группа: Пользователи Сообщений: 11 Пол: Мужской Репутация: 0 |
В общем, поясняю. У меня есть объект obj, содержащий метод move, который, в свою очередь, использует метод collide. От obj происходит объ. dot, тоже использующий НЕизмененный метод move, который _должен_ использовать измененный метод dot.collide, однако использует метод obj.collide. Видимо, для использования метода dot.c..... придется перекрывать метод move, а это долго. Есть методы без извращений?
-------------------- Если отладка - процесс удаления ошибок из программы, то программирование должно быть процессом их внесения.
|
NetAnton |
Сообщение
#2
|
Пионер Группа: Пользователи Сообщений: 112 Пол: Мужской Репутация: 0 |
"Баг с наследованием" - ну это не баг. а чтобы использовать метод предка, используй inherited move. но это, конечно, вызовет и родительский collide.
-------------------- Я люблю этот форум!
|
jaros |
Сообщение
#3
|
Гость |
Проблема решается с полпинка, если сделать метод collide виртуальным.
type Всё! Теперь, когда move вызывает метод collide, всегда вызывается правильный collide, а не только родительский. См. также Виртуальные функции и работа с ними |
NetAnton |
Сообщение
#4
|
Пионер Группа: Пользователи Сообщений: 112 Пол: Мужской Репутация: 0 |
пробовал виртуальные, дык Паскаль вылетает...
-------------------- Я люблю этот форум!
|
jaros |
Сообщение
#5
|
Группа: Пользователи Сообщений: 5 Пол: Мужской Репутация: 0 |
Как это вылетает? Не должен же вроде.
Ну-ка, с этого места поподробнее... |
BlackShadow |
Сообщение
#6
|
Гость |
Объясняю популярно.
Во-первых: Цитата чтобы использовать метод предка, используй inherited move. но это, конечно, вызовет и родительский collide Не правда. Ни к чему такому это не приведёт. Во-вторых. Паскаль действительно может вылетать при работе с объектами. Причиной это то, что в какоё-то момент идёт попытка вызова виртуального метода, а конструктор не ьыл вызван, т. е. VMT содержит полный бред! |
jaros |
Сообщение
#7
|
Группа: Пользователи Сообщений: 5 Пол: Мужской Репутация: 0 |
Ну тогда конечно... Кто же пишет объектно-ориентированно, но без виртуальных функций и конструкторов/деструкторов? По-моему, уж лучше тогда писать "как на C" -- т.е. без классов и наследования.
Извращенское решение поставленной задачи: заведите себе в классе obj переменную, которая будет показывать, объект ли это типа obj или всё-таки dot. Не забудьте их проинициализировать. В процедуре collide, которая должна быть только у obj, делаем проверку. Если переменная имеет значение 1, выполняем одни действия, если 2, то другие. Правильное (то есть объектно-ориентированное) решение: использовать виртуальные функции, завести конструктор и деструктор, создавать объект только посредством New, удалять объект после использования посредством Dispose. Научиться работать с указателями (хотя я надеюсь, что это вы знаете). Могу рассказать поподробнее. |
BlackShadow |
Сообщение
#8
|
Гость |
jaros, ну не обязательно лезть в динамическую память. Можно и по-проще. Например, если класс TMyObject имеет конструктор Create и деструктор Destroy, то можно просто и банально:
Код Var a:TMyObject; Begin a.Create; {...} a.Destroy End. Яркий пример - TV: Код Application.Init; Application.Run; Application.Done , если меня память не подводит. А вообще я не совсем понял твой "извращенский" вариант. Есть TypeOf - прекрасно подходит для проверки типа, а, что ты там ещё предложил... Ну это неважно. Главное ты сказал: классы - рулез, а наследование - неотъемлимая часть! |
jaros |
Сообщение
#9
|
Группа: Пользователи Сообщений: 5 Пол: Мужской Репутация: 0 |
TypeOf на самом деле возвращает указатель на таблицу виртуальных функций. Если он не проинициализирована конструктором (как у товарища), то typeof должен вернуть чушь. Сравнивать одну чушь с другой и надеяться, что они совпадут или не совпадут именно когда надо, я бы не стал... Но после конструктора всё должно быть в порядке.
|
BlackShadow |
Сообщение
#10
|
Гость |
Исключение составляет TypeOf(TMyObject), который берёт инфу совсем не из поля VMT
|
LHx |
Сообщение
#11
|
Новичок Группа: Пользователи Сообщений: 11 Пол: Мужской Репутация: 0 |
Поясните балде, что значат директивы constructor, destructor и virtual.
-------------------- Если отладка - процесс удаления ошибок из программы, то программирование должно быть процессом их внесения.
|
virt |
Сообщение
#12
|
Знаток Группа: Пользователи Сообщений: 419 Пол: Мужской Репутация: 6 |
грубо говоря ,конструктор -- метод который вызывается при создании объекта ,деструктор -- при уничтожении объекта.
виртуальные методы -- хз. -------------------- |
BlackShadow |
Сообщение
#13
|
Гость |
Конструктор - штука интересная. По сути это процедура, которая вызывается не ПРИ создании, а ДЛЯ создания объекта. Он имеет Параметр №0 и строчку №0. Параметр №0, это как в любом другом методе - Self, то есть ссылка на экземпляр класса, вызвавшего метод. Сточка №0 куда интереснее. Она проверяет Self на Nil. Если это так, то объект располагается в динамической памяти. В таком случае нужно ему её выделить, что конструктор и делает. Затем смотрит, имеет ли этот класс виртуальные методы. Если имеет, то заполняет его поле VMT (поле №0 ) адресом VMT Этого класса. Затем уж происходит вызов того, что ты сам насочинял. Параметр Self к этому времени имеет уже корректное значение.
Мало того конструктор - единственная функция, которая может быть вызвана без сохранения результатов при любой настройки компилятора. Да-да, именно функция. И та необычная. Её результат можно использовать как Boolean (для проверки вызова Fail в теле конструктора), как Pointer, чтобы узнать где расположился твой объект, и как указатель на экземпляр какого-то там класса. Деструктор - штука более банальная. Он вызывается ПРИ уничтожении объекта и служит как правило для освобождения ресурсов занятых под нужды объекта. Например для класса списка, логично освобождать в нём память, а для файла - закрывать его. Виртуальные функции - основа ООП. Вот тебе пример из ЛЮБОЙ книжки по паскалю, где вообще этот вопрос задевается: Код Uses Graph,CRT; Type TFigure=Object x:Integer; y:Integer; Constructor Create(ax,ay:Integer); Procedure Draw;Virtual; Destructor Destroy;Virtual; End; TRound=Object(TFigure) r:Integer; Constructor Create(ax,ay,ar:Integer); Procedure Draw;Virtual; Destructor Destroy;Virtual; End; TRect=Object(TFigure) a:Integer; b:Integer; Constructor Create(ax,ay,aa,ab:Integer); Procedure Draw;Virtual; Destructor Destroy;Virtual; End; Constructor TFigure.Create(ax,ay:Integer); Begin x:=ax; y:=ay End; Procedure TFigure.Draw; Begin End; Destructor TFigure.Destroy; Begin End; Constructor TRound.Create(ax,ay,ar:Integer); Begin Inherited Create(ax,ay); r:=ar End; Procedure TRound.Draw; Begin SetColor(Red); Circle(x,y,r) End; Destructor TRound.Destroy; Begin SetColor(Black); Circle(x,y,r) End; Constructor TRect.Create(ax,ay,aa,ab:Integer); Begin Inherited Create(ax,ay); a:=aa; b:=ab End; Procedure TRect.Draw; Begin SetColor(Red); Rect(x,y,x+a,x+b) End; Destructor TRect.Destroy; Begin SetColor(Black); Rect(x,y,x+a,x+b) End; Var a:Array[0..99] Of ^TFigure; i:Integer; Begin {InitGraph там какой-нибудь...} For i:=Lo(a) To Hi(a) Do If Random(2)=1 Then a[i]:=New(TRound,Create(Random(GetMaxX),Random(GetMaxY),Random(100)) Else a[i]:=New(TRect,Create(Random(GetMaxX),Random(GetMaxY),Random(100),Random(100)); For i:=Lo(a) To Hi(a) Do a[i]^.Draw; ReadKey; For i:=Lo(a) To Hi(a) Do Dispose(a[i],Destroy); ReadKey; RestoreCRTMode End. Уф... Запарился пока писал. Попробуй разберись сам - тут всё примитивно. Если что - спрашивай. Суть виртуальных примерно такая - они могут заменять или дополнять функции предков. В этом примере конструктор (он всегда типа виртуальный) дополняет метод предка, а процедура Draw - заменяет. З. Ы. : а вообще, Oleg_Z писал введение в ООП и закреплял его, по-моему. Там-то должно быть про это всё рассказано. |
Romtek |
Сообщение
#14
|
Знаток Группа: Пользователи Сообщений: 303 Пол: Мужской Реальное имя: Роман Репутация: 2 |
virtual; - когда нужно перекрыть метод.
Например, есть метод Draw для отрисовки какой-то фигуры. Если необходимо изменить только отрисовку объекта, то нет нужды писать новый объект, а надо просто "перекрыть" новым методом. Код Type TCircle = object (TGraphObject) procedure Draw; end; TFilledCircle = object (TCircle) filled: boolean; procedure Draw; virtual; { перекрытие метода } end; procedure TFilledCircle.Draw; begin if Filled then Inherited.Draw { рисуем окружность } else begin { рисуем заполненную окружность (круг) } end; end; -------------------- Romiras HomeLab- материалы и статьи по разработке ПО, моделирование алгоритмов, обработка и анализ информации, нейронные сети, машинное зрение и прочее.
|
BlackShadow |
Сообщение
#15
|
Гость |
Не обязательно перекрыть! Можно просто дополнить. Например:
Код Type TCollection=Object {...} Procedure Add(Item:SomeType);Virtual; {...} End; TSortedCollection=Object(Collection) Procedure Sort; Procedure Add(Item:SomeType);Virtual; End; Procedure TCollection.Add(Item:SomeType); Begin {...} End; Procedure TSortectCollection.Sort; Begin {...} End; Procedure TSortedCollection.Add(Item:SomeType); Begin Inherited Add(Item); {Вызов метода предка} Sort End; {...} |
Romtek |
Сообщение
#16
|
Знаток Группа: Пользователи Сообщений: 303 Пол: Мужской Реальное имя: Роман Репутация: 2 |
Тему в "Теоретические" ?
-------------------- Romiras HomeLab- материалы и статьи по разработке ПО, моделирование алгоритмов, обработка и анализ информации, нейронные сети, машинное зрение и прочее.
|
BlackShadow |
Сообщение
#17
|
Гость |
Согласен. Тут она не в теме
|
w0w |
Сообщение
#18
|
Гость |
никак не понял где faq. ну ладно.
хочу научиться использовать меню.. паскаль сказал, что есть на этот счет объект TMenuView, но образца не нашел. и не работал с объектами както раньше. не напишите коротенький код для простейшего меню? Не в тему. Создай свой топик в нужном разделе. Сообщение отредактировано: APAL - |
Текстовая версия | 26.04.2024 4:43 |