Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Проверка существования метода потомков в родителе


Автор: Bose 27.10.2005, 13:49

Надо в форме-родителе вызвать метод который будет реализован в некоторых формах-наследниках(не во всех). Т.е. сначала надо проверить, существует ли этот метод в наследнике и, если существует, то вызвать его.

Класс-родитель:
Код

  TcsForm = class(TForm)
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  ...
  published
      procedure RefreshData; virtual; abstract;
  end;

procedure TcsForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
     if Key=VK_F5 then
     begin
          if TcsForm(Sender).MethodAddress(RefreshData)<>nil then Caption:='ok' else Caption:='Sux';
     end;
end;

сейчас получается, что проверка TcsForm(Sender).MethodAddress(RefreshData)<>nil всегда даёт True smile

Автор: maxim1000 27.10.2005, 13:52
уже не помню, как с этим в Delphi, но вообще, abstract приводит к тому, что если его не переопределить, то даже объект создать такой нельзя - компилятор не позволит...

Автор: Bose 27.10.2005, 13:59
хммм.... у меня создается... почему-то smile
но не суть... мне все-равно, будет там abstract или нет... около 40 форм уже сделано. и где-то примерно в 20 реализован метод RefreshData. И нужно сделать так, чтобы этот метод вызывался по нажатию на F5.
Я заменил предка для всех форм с TForm на свою TcsForm (Search & Replace). И в TcsForm пытаюсь проверить, реализован ли этот метод в той форме из которой пришло событие OneKeyDown...

Автор: maxim1000 27.10.2005, 14:22
ну тогда можно сделать так:
1. делаем в предке переменную (на всякий случай в private, чтобы никто из потомков не изменил)
2. реализовываем в предке эту функцию и пишем туда flag:=false, больше она ничего не делает

перед вызовом делаем flag:=true
вызываем функцию
проверяем flag

Автор: Bose 27.10.2005, 14:34
но тогда я не смогу вызвать одноименный метод, реализованный в потомке smile
т.е. каждый раз, когда я буду вызывать этот метод в предке, у меня будет вызываться метод, который только и умеет, что изменять флаг smile

Автор: maxim1000 27.10.2005, 14:36
Цитата
но тогда я не смогу вызвать одноименный метод, реализованный в потомке

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

Автор: Bose 27.10.2005, 15:19
получилось!
Спасибо, maxim1000!
Я до сих пор не могу осмыслить всей гибкости предостовляемой ОбьектноОриентированным Программированием, и черезвычайно радуюсь, когда удается узнать новый прием. smile

В общем я сделал так:

в предке создал пустой виртуальный метод RefreshData
Код

TcsForm = class(TForm)    
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);    
  ...    
  published    
      procedure RefreshData; virtual; 
  end;    

procedure TcsForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);    
begin    
     if Key=VK_F5 then    RefreshData;
end;

procedure TcsForm.RefreshData;
begin
     //void
end;


а ко всем обьявлениям RefreshData в потомках, добавил директиву override; (заработало все только после добавления override)

только я все-равно не понимаю, почему оно не работало, без override. как я себе представлял, override же должен был прятать метод TcsForm.RefreshData, что мне совсем не должно было мешать... А на деле оказалось совсем наоборот... smile

Автор: <Spawn> 27.10.2005, 15:25
Это можно запросто реализовать через интерфейсы:

Код

//Базовый класс
TMyClass = class(TObject)
end;

//Интерфейс 
//GUID в данном случае не обязателен
IMyInterface = interface(IInterface)
  procedure HelloWorld;
end;

//Класс, реализующий методы интерфейса IMyInterface
TMyClass2 = class(TMyClass, IMyInterface)
  procedure HelloWorld;
end;

TMyClass2 = class(TMyClass)
//Какие то методы класса
end;

var
  MyClassInstance: TMyClass;

//Где то в программе инициализируется указатель на экзмепляр класса MyClassInstance, тогда для определения доступености метода используем наш интерфейс

if MyClassInstance is IMyInterface then
  (MyClassInstance as IMyInterface).HelloWorld;

Автор: <Spawn> 27.10.2005, 15:35
Цитата(Bose @ 27.10.2005, 17:19)
только я все-равно не понимаю, почему оно не работало, без override. как я себе представлял, override же должен был прятать метод TcsForm.RefreshData, что мне совсем не должно было мешать... А на деле оказалось совсем наоборот... smile

override ни чего не прячет! Он указывает компилятору создать нужные связи в VMT(Virtual Method Table, если не ошибаюсь) таблице для того, чтобы методы экземпляра класса наследника можно было вызвать из переменной класса предка. Т.е.:

Код

TMyClass = class
  procedure Hi; virtual;
end;

procedure TMyClass.Hi;
begin
  ShowMessage('hi');
end;

TMyClass2=class(TMyClass)
  procedure Hi; override;
end;

procedure TMyClass2.Hi;
begin
  inherited;
  ShowMesage('Hi from TMyClass2 instance');
end;

TMyClass3 = class(TMyClass)
  procedure Hi; 
end;

procedure TMyClass3.Hi;
begin
  ShowMessage('blabalbla');
end;

var
  MyClassInstance: TMyClass;
begin
  //При использовании переопределенного виртуального метода (через директиву override)
  //ты должен будешь увидеть 2 сообщения(предка и наследкника. Сообщение предка вызывается из зи включения его кода директивой inherited)
  MyClassInstance := TMyClass2.Create;  
  MyClassInstance.Hi;
  ...
  //В данном же случае ты увидишь только вызов метода предка
  MyClassInstance := TMyClass3.Create;  
  MyClassInstance.Hi;
end;

Автор: Bose 27.10.2005, 16:39
<Spawn>
Я имел в виду, что вот здесь:
Код

//В данном же случае ты увидишь только вызов метода предка    
  MyClassInstance := TMyClass3.Create;    
  MyClassInstance.Hi;

с моей точки зрения должен был бы сработать TMyClass3.Hi; а не TMyClass.Hi, а применение директивы override при обьявлении TMyClass3.Hi, позволило бы вызвать TMyClass.Hi из TMyClass3.Hi.
Короче, я ошибался. =)

p.s. Вот такие вот подробные обьяснения, было бы неплохо включать в FAQ Vingrad'a... smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)