Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 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]

Всем большое спасибо за участие в дискуссии, а особенно Юрию Зотову!!!




Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.10;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.76 MB
Время: 0.026 c
1-28511           VadX                  2001-12-21 15:29  2002.01.10  
Вопрос


14-28536          tovSuhov              2001-11-16 15:39  2002.01.10  
E-mail автоответчик


3-28408           urii                  2001-12-07 17:26  2002.01.10  
перенос


1-28493           vbazik                2001-12-21 13:16  2002.01.10  
Помогите с графикой, please :-(


1-28479           ЙЦУЙУ                 2001-12-22 14:46  2002.01.10  
ПО МО Г И ТЕ