Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
1-28468
avr555
2001-12-21 16:50
2002.01.10
Сделать компонент поверх всех.


1-28512
MaXimka
2001-12-21 17:12
2002.01.10
Как узнать текущее разрешение экрана?


3-28405
Desdechado
2001-12-05 16:09
2002.01.10
IB по модемному каналу


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


4-28563
Дремучий
2001-11-09 14:43
2002.01.10
Все свободны. А Вас, Штирлиц, я попрошу задержаться.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский