Форум: "Основная";
Текущий архив: 2002.01.10;
Скачать: [xml.tar.bz2];
ВнизКак наследовать метод не родителя, а родителя родителя? Найти похожие ветки
← →
Knyaz17 (2001-12-21 11:47) [0]Господя, подскажите пожалуйста, как можно отнаследоавть метод не родителя, а родителя родителя? То есть есть три класса class1, Class2, Class3.
Они отнаследованы в порядке перичисления, есть метод в Class3.
Как сделать чтобы выполнялся метод в Class1, а потом сразу в Class3???
← →
Юрий Зотов (2001-12-21 11:57) [1]Уточните - имеется в виду виртуальный (динамический) метод?
← →
Ю Ю (2001-12-21 11:58) [2]Значит Class2 вовсе и не родитель Class3, раз его метод не удовлетворяет наследника :-) Наследуй непосредственно от Class1
← →
McSimm (2001-12-21 12:03) [3]Если имеется в виду виртуальный (динамический) метод
и если я не ошибаюсь,
то можно
procedure TClass3.SomeMethod;
begin
// Ваш код
TClass1.SomeMethod
// Ваш код
end
← →
Knyaz17 (2001-12-21 12:03) [4]To Ю Ю:
Остальные методы, кроме этого, нужно наследовать от Class2.
← →
Knyaz17 (2001-12-21 12:16) [5]А как мне объявить виртуальный (динамический) метод?
Я делаю в Classs1:
procedure Go; virtual;
а в Class2, Class3:
procedure Go; override;
и ничего не получается, если я делаю:
procedure TClass3.Go;
begin
TClass1.Go;
end
то компилятор ругается.
← →
Digitman (2001-12-21 12:20) [6]не нужно TClass1.Go делать виртуальным.
TClass1 = class(...)
procedure Go;
end;
TClass2 = class(TClass1)
procedure Go;
end;
TClass3 = class(TClass2)
procedure Go;
end;
procedure TClass3.Go;
begin
TClass1(Self).Go;
TClass2(Self).Go;
Go;
end;
← →
Knyaz17 (2001-12-21 12:22) [7]Или что делать если метод не виртуальный?
Можно сделать как нибудь через конструкцию
inherited?
что-то типа
procedure TClass3.Go;
begin
inherited TClass1.Go;
end
← →
Knyaz17 (2001-12-21 12:33) [8]To Digitman:
у меня есть структура модулей и в них не 3, а много классов наследуются,
и организовано это следующим образом:
TClass1 = class(...)
procedure Go; override;
end;
TClass2 = class(TClass1)
procedure Go; override;
end;
TClass3 = class(TClass2)
procedure Go; override;
end;
соответственно мне не надо вызывать метод Go класса Class2, но желательно
только в Class3.
← →
Юрий Зотов (2001-12-21 12:34) [9]Привожу работающий пример (см. книгу Сергея Орлика "Секреты Delphi на примерах"). В проекте - три формы, отнаследованные одна от другой по цепочке. При нажатии на кнопку показывается сообщение с именем формы. В классе TForm3 перед этим вызывается виртуальный метод "деда" (именно так, сразу "деда" - напрямую, а не через "отца"). Что мы и видим на экране.
Фокус в том, что перед вызовом метода подменяется вход в VMT (потом он, конечно, должен быть восстановлен). В итоге класс TForm3 как бы временно становится классом TForm1. Причем таким образом можно вызвать вообще любой метод любого класса, независимо от отношений наследования.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, PInfoViewer, Grids, DBGrids;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
public
procedure VirtualMethod; virtual;
end;
var
Form1: TForm1;
implementation
uses
Unit2, Unit3;
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
VirtualMethod
end;
procedure TForm1.VirtualMethod;
begin
ShowMessage("Form1")
end;
procedure TForm1.FormShow(Sender: TObject);
begin
Form2.Show;
Form3.Show
end;
end.
=========================================================================
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Unit1, StdCtrls;
type
TForm2 = class(TForm1)
public
procedure VirtualMethod; override;
end;
var
Form2: TForm2;
implementation
{$R *.DFM}
procedure TForm2.VirtualMethod;
begin
ShowMessage("Form2")
end;
end.
=========================================================================
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Unit2, StdCtrls;
type
TForm3 = class(TForm2)
public
procedure VirtualMethod; override;
end;
var
Form3: TForm3;
implementation
{$R *.DFM}
type
PClass = ^TClass;
procedure TForm3.VirtualMethod;
var
OldClass: TClass;
begin
OldClass := PClass(Self)^;
PClass(Self)^ := ClassParent.ClassParent;
try
VirtualMethod
finally
PClass(Self)^ := OldClass
end;
ShowMessage("Form3")
end;
end.
← →
Алексей Петров (2001-12-21 12:50) [10]> Юрий Зотов.
Это уже чистое хаккерство, основанное на не документированном факте, что экземпляр объекта начинается с указателя на VMT.
Чисто теоретически, в очередной версии Delphi это может перестать работать. Хотя я почти уверен, что Borland этот факт оставят верным "на вечно" :)
К стати, методика годится и для вызова динамического метода дедушки без изменений.
← →
Alx2 (2001-12-21 12:53) [11]Жуть :)))
Можно, конечно, но стоит ли так извращаться через RTTI?
Может, использовать object вместо class. Там можно напрямую вызвать метод любого из предков. Хотя, конечно, теряются другие прелести.
Но, скорее всего, такие проблемы возникают из-за неподходяще построеной иерархии классов.
← →
McSimm (2001-12-21 12:53) [12]Извиняюсь за непроверенный ответ.
Перепутал с конструктором.
← →
Knyaz17 (2001-12-21 12:57) [13]Да, но не годится, если в методе класса1 другой такой же наследуемый во всех классах метод!!!
То есть у меня есть:
TClass1 = class(...)
procedure Go; override;
procedure Refresh; override;
end;
TClass2 = class(TClass1)
procedure Go; override;
procedure Refresh; override;
end;
TClass3 = class(TClass2)
procedure Go; override;
procedure Refresh; override;
end;
и метод Refresh срабатывает в Go для Class1!!!, а в Class3 он переопределен, и должен срабатывать.
← →
Knyaz17 (2001-12-21 13:01) [14]Предыдущий мой ответ был ответом на сообщение Юрия Зотова.
← →
Владислав (2001-12-21 13:18) [15]Привел бы реальный код (часть его).
← →
Юрий Зотов (2001-12-21 13:27) [16]> Knyaz17 (21.12.01 13:01)
А что мешает использовать тот же прием в TClass1.Go и в итоге вызвать из него TClass3.Refresh? Более того, метод Go можно определить с параметром:
procedure Go(AClass: TClass = nil); virtual;
Тогда TClass3 вызывает его, как Go(OldClass), а TClass1 в итоге получает именно тот класс, чей метод Refresh надо вызвать.
← →
Knyaz17 (2001-12-21 13:32) [17]Всем большое спасибо за участие в дискуссии, а особенно Юрию Зотову!!!
← →
Юрий Зотов (2001-12-21 13:39) [18]> Алексей Петров © (21.12.01 12:50)
> Это уже чистое хаккерство, основанное на не документированном факте,
> что экземпляр объекта начинается с указателя на VMT.
Почему недокументированном? Вот цитата из хелпа Delphi 5 (ключевое слово для поиска - VMT)
"The first 4-byte field of every object is a pointer to the virtual method table (VMT) of the class."
Значит, все вполне легально. И в будущих версиях не изменится.
← →
Knyaz17 (2001-12-21 13:43) [19]Всем большое спасибо за участие в дискуссии, а особенно Юрию Зотову!!!
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2002.01.10;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.003 c