IPB
ЛогинПароль:

> Правила раздела!

1. Заголовок или название темы должно быть информативным !
2. Все тексты фрагментов программ должны помещаться в теги [code] ... [/code] или [code=pas] ... [/code].
3. Прежде чем задавать вопрос, см. "FAQ" и используйте ПОИСК !
4. НЕ используйте форум для личного общения!
5. Самое главное - это раздел теоретический, т.е. никаких задач и программ (за исключением небольших фрагментов) - для этого есть отдельный раздел!

 
 Ответить  Открыть новую тему 
> Проблема с ООП, Баг с наследованием.
сообщение
Сообщение #1


Новичок
*

Группа: Пользователи
Сообщений: 11
Пол: Мужской

Репутация: -  0  +


В общем, поясняю. У меня есть объект obj, содержащий метод move, который, в свою очередь, использует метод collide. От obj происходит объ. dot, тоже использующий НЕизмененный метод move, который _должен_ использовать измененный метод dot.collide, однако использует метод obj.collide. Видимо, для использования метода dot.c..... придется перекрывать метод move, а это долго. Есть методы без извращений?


--------------------
Если отладка - процесс удаления ошибок из программы, то программирование должно быть процессом их внесения.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Пионер
**

Группа: Пользователи
Сообщений: 112
Пол: Мужской

Репутация: -  0  +


"Баг с наследованием" - ну это не баг. а чтобы использовать метод предка, используй inherited move. но это, конечно, вызовет и родительский collide.


--------------------
Я люблю этот форум!
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Гость






Проблема решается с полпинка, если сделать метод collide виртуальным.

type
obj = object
...
procedure move;
procedure collide; virtual;
...
end;
dot = object (obj)
...
{ процедуры move нету -- она родительская }
procedure collide; virtual;
...
end;


Всё! Теперь, когда move вызывает метод collide, всегда вызывается правильный collide, а не только родительский.

См. также Виртуальные функции и работа с ними
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Пионер
**

Группа: Пользователи
Сообщений: 112
Пол: Мужской

Репутация: -  0  +


пробовал виртуальные, дык Паскаль вылетает... angry.gif


--------------------
Я люблю этот форум!
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5





Группа: Пользователи
Сообщений: 5
Пол: Мужской

Репутация: -  0  +


huh.gif Как это вылетает? Не должен же вроде.

Ну-ка, с этого места поподробнее...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гость






Объясняю популярно.
Во-первых:
Цитата
чтобы использовать метод предка, используй inherited move. но это, конечно, вызовет и родительский collide

Не правда. Ни к чему такому это не приведёт.

Во-вторых. Паскаль действительно может вылетать при работе с объектами. Причиной это то, что в какоё-то момент идёт попытка вызова виртуального метода, а конструктор не ьыл вызван, т. е. VMT содержит полный бред!
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7





Группа: Пользователи
Сообщений: 5
Пол: Мужской

Репутация: -  0  +


Ну тогда конечно... Кто же пишет объектно-ориентированно, но без виртуальных функций и конструкторов/деструкторов? По-моему, уж лучше тогда писать "как на C" -- т.е. без классов и наследования.

Извращенское решение поставленной задачи: заведите себе в классе obj переменную, которая будет показывать, объект ли это типа obj или всё-таки dot. Не забудьте их проинициализировать. В процедуре collide, которая должна быть только у obj, делаем проверку. Если переменная имеет значение 1, выполняем одни действия, если 2, то другие.

Правильное (то есть объектно-ориентированное) решение: использовать виртуальные функции, завести конструктор и деструктор, создавать объект только посредством New, удалять объект после использования посредством Dispose. Научиться работать с указателями (хотя я надеюсь, что это вы знаете).

Могу рассказать поподробнее.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Гость






jaros, ну не обязательно лезть в динамическую память. Можно и по-проще. Например, если класс TMyObject имеет конструктор Create и деструктор Destroy, то можно просто и банально:
Код

Var
 a:TMyObject;
Begin
 a.Create;
 {...}
 a.Destroy
End.

Яркий пример - TV:
Код

Application.Init;
Application.Run;
Application.Done

, если меня память не подводит.

А вообще я не совсем понял твой "извращенский" вариант. Есть TypeOf - прекрасно подходит для проверки типа, а, что ты там ещё предложил... Ну это неважно. Главное ты сказал: классы - рулез, а наследование - неотъемлимая часть!
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9





Группа: Пользователи
Сообщений: 5
Пол: Мужской

Репутация: -  0  +


TypeOf на самом деле возвращает указатель на таблицу виртуальных функций. Если он не проинициализирована конструктором (как у товарища), то typeof должен вернуть чушь. Сравнивать одну чушь с другой и надеяться, что они совпадут или не совпадут именно когда надо, я бы не стал... Но после конструктора всё должно быть в порядке.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Гость






Исключение составляет TypeOf(TMyObject), который берёт инфу совсем не из поля VMT smile.gif
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Новичок
*

Группа: Пользователи
Сообщений: 11
Пол: Мужской

Репутация: -  0  +


Поясните балде, что значат директивы constructor, destructor и virtual. blink.gif


--------------------
Если отладка - процесс удаления ошибок из программы, то программирование должно быть процессом их внесения.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Знаток
****

Группа: Пользователи
Сообщений: 419
Пол: Мужской

Репутация: -  6  +


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


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #13


Гость






Конструктор - штука интересная. По сути это процедура, которая вызывается не ПРИ создании, а ДЛЯ создания объекта. Он имеет Параметр №0 и строчку №0. Параметр №0, это как в любом другом методе - Self, то есть ссылка на экземпляр класса, вызвавшего метод. Сточка №0 куда интереснее. Она проверяет Self на Nil. Если это так, то объект располагается в динамической памяти. В таком случае нужно ему её выделить, что конструктор и делает. Затем смотрит, имеет ли этот класс виртуальные методы. Если имеет, то заполняет его поле VMT (поле №0 smile.gif ) адресом 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 писал введение в ООП и закреплял его, по-моему. Там-то должно быть про это всё рассказано.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #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- материалы и статьи по разработке ПО, моделирование алгоритмов, обработка и анализ информации, нейронные сети, машинное зрение и прочее.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #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;

{...}

 К началу страницы 
+ Ответить 
сообщение
Сообщение #16


Знаток
****

Группа: Пользователи
Сообщений: 303
Пол: Мужской
Реальное имя: Роман

Репутация: -  2  +


Тему в "Теоретические" ?


--------------------
Romiras HomeLab- материалы и статьи по разработке ПО, моделирование алгоритмов, обработка и анализ информации, нейронные сети, машинное зрение и прочее.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #17


Гость






Согласен. Тут она не в теме smile.gif
 К началу страницы 
+ Ответить 
сообщение
Сообщение #18


Гость






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

Не в тему. Создай свой топик в нужном разделе.

Сообщение отредактировано: APAL -
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 26.04.2024 4:43
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name