Страница 2 из 2

Re: Вызов методов потомка?

Добавлено: 27.05.2010 19:59:52
скалогрыз
dionic писал(а):Народ всем привет!
Подскажите кто знает...
Каким образом, если вообще возможно, можно вызвать метод потомка, у объекта класса родителя, если у родителя этот метод вообще не объявлен?

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

я знаю кучу хороших программ (например fp-компилятор и Лазарус), написанных на паскале, которые успешно работают, без этаких извращений. А всё почему - правильное использование ООП :)

"как легче вкручивать шурупы молотком?!"

Re: Вызов методов потомка?

Добавлено: 27.05.2010 20:12:54
VirtUX
Mr.Smart писал(а):Самый простой и правильный способ будет создание в родители данного только пустого, а в наследниках перекрывать его.

Извиняюсь за ламерство. А как (этот пустой) потом вызывать в родительском? А если этих методов несколько (в дочернем)? И если неизвестно заранее сколько этих методов (дочерних) нужно будет вызвать в родительском?
Просто у меня похожая ситуация, но пока кода мало я решаю проблему топором (по типу как тут уже писал). За разжевывание - отдельная благодарочка.

Re: Вызов методов потомка?

Добавлено: 27.05.2010 20:53:07
and
Ну, ещё можно в сторону GetMethodProp посмотреть.

Re: Вызов методов потомка?

Добавлено: 28.05.2010 00:04:13
Odyssey
VirtUX писал(а):property ChildMethod: TObjProcedure;

Это те же обработчики событий, типа TButton.OnClick, которые используется во всех LCL/VCL контролах. Проверено временем, правда используется в основном там, где нужно устанавливать нужный метод извне.

VirtUX писал(а):А как (этот пустой) потом вызывать в родительском?

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

Код: Выделить всё

TParent = class
  procedure ChildMethod; virtual; // пустой, если лень писать begin end;
                                  // можно написать abstract; после virtual.
end;

TChild = class(TParent)
  procedure ChildMethod; override;
end;

Теперь если сделать так:

Код: Выделить всё

var
  obj: TParent;
begin
  obj := TChild.Create;
  obj.ChildMethod();
  FreeAndNil(obj);
end;

То будет вызван именно TChild.ChildMethod, несмотря на то, что переменная типа TParent. Это потому, что метод определяется не по объявленному в var типу, а по реально созданному, т.е. чей конструктор мы вызывали. Виртуальные методы сделаны именно для описываемой цели. Другое дело, что топикстартер, зная об этом, почему то сознательно не хотел этот способ использовать, о чём и предупредил. Поэтому ему я не предлагал.

VirtUX писал(а):А если этих методов несколько (в дочернем)?

Можно создавать для каждого виртуальный метод в родителе, а можно вообще отказаться от такого наследования. Наследование по сути -- лишь способ повторного использования функциональности без дублирования кода. Если у потомков одного родителя настолько разная функциональность, что не хочется объединять её в родителе, то может и ну его?

VirtUX писал(а):И если неизвестно заранее сколько этих методов (дочерних) нужно будет вызвать в родительском?
Если неизвестно на этапе проектирования родителя, т.е. родитель после окончания и заморозки своего кода должен будет вызывать произвольное количество неизвестных ему методов, то наверное только на основе списка таких обработчиков, которые вы описали несколькими постами выше.

Вообще, есть две мысли:
1) Реальный пример лучше бы помог найти хорошее решение. Пока мы рассуждаем на TParent и TChild со стороны всё кажется элементарным, логично решающимся с помощью виртуальных методов.
2) Оффтоп: для случаев, когда "заранее неизвестно", у кого, чего и сколько вызвать, Pascal -- не самый эффективный язык. Строгая типизация и проверки до рантайма помогают ловить ошибки, но это иногда здорово связывает руки. Возможно для таких частей системы стоит взглянуть на что-нибудь динамическое, типа Lua.

Re: Вызов методов потомка?

Добавлено: 28.05.2010 08:41:00
dionic
Odyssey спасибо ,конечно, за разъяснение виртуальных методов=), это было самое очевидное решение, и оно у меня сейчас и применено.
Я просто думал, что возможно найдётся какой-то обход данного случая... Постараюсь привести сегодня реальный пример кода... Просто незнаю насколько это получится...

Re: Вызов методов потомка?

Добавлено: 28.05.2010 10:43:19
VirtUX
Odyssey писал(а):var
obj: TParent;
begin
obj := TChild.Create;

Вот это, как писал dionic, подходит для частного случая. Т.е. мы заранее знаем, с каким дочерним классом работаем. Но если класс создан

Код: Выделить всё

obj := TParent.Create;
и нужно вызвать метод дочернего (может TChild, а может и TChild2) класса, то это не прокатит.

Re: Вызов методов потомка?

Добавлено: 28.05.2010 10:46:19
dionic
Почему не прокатит, всё прокатит с виртуальными методами , у меня прокатывает же. Вопрос как раз в том как сделать тоже самое но что бы не трограть родителя , т.е. не добавлять виртуальных методов ему и не перекрывать их в потомках...=)

На самом деле obj просто объявлен как TParent, а на этапе работы он TChild.

Re: Вызов методов потомка?

Добавлено: 28.05.2010 11:48:56
Odyssey
VirtUX писал(а):Но если класс создан

Код: Выделить всё

obj := TParent.Create;
и нужно вызвать метод дочернего (может TChild, а может и TChild2) класса, то это не прокатит.

Да, в этом случае не прокатит ничего из вышеупомянутого, кроме обработчиков событий. Ведь методов этих у парента просто нет. И слово "дочерний" в данном случае ни к чему не обязывает, с тем же успехом можно пытаться у класса A вызвать методы независимого от него класса B. При наследовании только дочерние классы знают о родителях и могут повторно использовать их код, а родительские классы ничего не знают о дочерних. В зависимости от конкретного случая, можно попробовать "вывернуть" иерархию (т.е. обратить цепочку наследования), или использовать интерфейсы.

Re: Вызов методов потомка?

Добавлено: 28.05.2010 16:43:15
Timid
Вообще-то для этого есть понятие виртуального метода. Ключевое слово virtual.
Метод определенный как виртуальный можно не описывать в родителе, всегда будет вызываться последний перекрытый метод. Даже при использовании inherited для вызова родительского метода (в котором есть вызов виртуального метода)