Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.07.24;
Скачать: CL | DM;

Вниз

Проверка, абстрактный ли метод   Найти похожие ветки 

 
Юрий Федоров ©   (2003-07-11 14:14) [0]

Необходимо осуществить сабж. Вариант "вызвать и посмотреть, что получится" не подходит, так как если он окажется неабстрактным, его вызов в данном месте программы не нужен.
Хочется просто скрыть некоторые элементы управления (пункты меню) в реализации формы-предка, в которой этот метод абстрактный.
Это вообще возможно теоретически?


 
Skier ©   (2003-07-11 14:19) [1]

>Юрий Федоров © (11.07.03 14:14)


> Хочется просто скрыть некоторые элементы управления (пункты
> меню) в реализации формы-предка, в которой этот метод абстрактный.




Кроме проверки в try-except-end блоке ничего сказать не могу...
Но, может быть попробовать (как вариант) использовать в предке
не абстрактные методы, а пустые, т.е.

procedureTSomeClass.SomeMethod;
begin
//do nothing...
end;

Хотя тоже будет присутствовать лишний вызов



 
Юрий Федоров ©   (2003-07-11 14:27) [2]

В общем, понятно, что можно обойти эту ситуацию, просто хочется красивого решения. И я вовсе не боюсь Exception"а, гораздо хуже, если наживаешь кнопку, и ничего не происходит.
Просто мне кажется, что проблему можно решить с помошью вставки на ассемблере, а я в нем к сожалению не силен


 
Skier ©   (2003-07-11 14:32) [3]

>Юрий Федоров © (11.07.03 14:27
> Просто мне кажется, что проблему можно решить с помошью
> вставки на ассемблере

Не уверен, но если можно то только (если не считать Exception"а) через VMT


 
Юрий Федоров ©   (2003-07-11 14:35) [4]

>>Skier © (11.07.03 14:32)
Ну да, о том и речь


 
Skier ©   (2003-07-11 14:38) [5]

Вот, может как-то поможет :
www.rsdn.ru
номер за 02.2003
статья : "Обработка абстрактных методов в Delphi"


 
Толик ©   (2003-07-11 14:39) [6]

Есть такая штука: зовётся vmtoffset. Она даже в хелпах описана. Идея заключается в следующем: известно, что во время компиляции на место всех абстрактных методов в VMT класса подставляется указатель на AbstractError. На этом можно и сыграть.


type
TAbstract = class(TObject)
private
procedure F(); virtual; abstract;
end;

теперь по адресу pointer(pointer(TAbstract)^) лежит тот самый указатель, единый для ВСЕХ абстрактных методов. Затем через vmtoffset получаем смещение проверяемой функции в VMT нашего класса и сравниваем два указателя. Если они равны => наш метод - абстрактный.


 
Palladin ©   (2003-07-11 14:42) [7]

может организовать что то на подобие этого


TAbstractClass=class
protected
m_RMethods:TStringList;
private
procedure AddRMethod(p_strMethodName:strring);
public

procedure Method1; virtual; abstract;
procedure Method2; virtual; abstract;

function IsRealized(p_strMethodName:string):integer;
constructor Create;
destructor destroy;
end;

procedure TAbstractClass.AddRMethod;
begin
m_RMethods.Add(p_strMethodName);
end;

function TAbstractClass.IsRealized;
begin
m_RMethods.Find(p_strMethodName,result);
end;

constructor TAbstractClass.Create;
begin
inherited;
m_RMethods:=TStringList.Create;
m_RMethods.Sorted:=true;
end;

destructor TAbstractClass.Destroy;
begin
m_RMethods.free;
end;

type
TClass1=class(TAbstractClass)
public
procedure Method1; override;
constructor Create;
end;

procedure TClass1.Method1;
begin
// SomeAction
end;

constructor Create;
begin
inherited
AddRMethod("Method1");
end;

определять через IsRealized...


 
Skier ©   (2003-07-11 14:43) [8]

>Толик © (11.07.03 14:39)
Если я помню, то нет возможности определить где кончается
VMT, чтобы пробежаться в цикле.
Если я не прав - пардон !


 
Толик ©   (2003-07-11 14:48) [9]

to Skier © (11.07.03 14:43)
а циклом и не надо бегать:

var
i: longword;
asm
mov i, vmtoffset TMyName.MyProc
end;

получаем смещение MyProc в VMT класса TMyClass. Оно определяется на момент компиляции. Нуи остаётся только посмотреть, не лежит ли там то же, что и в pointer(pointer(TAbstract)^)


 
Skier ©   (2003-07-11 14:50) [10]

>Толик © (11.07.03 14:48)
Угу ! Твоя правда ! :)


 
Толик ©   (2003-07-11 15:29) [11]

to Юрий Федоров © (11.07.03 14:27)
В общем, понятно, что можно обойти эту ситуацию, просто хочется красивого решения.

Наконец-то нашёл время накидать пример.

type
TAbstract = class(TObject)
private
procedure AbstractPtr(); virtual; abstract;
end;

TParent = class(TObject)
public
procedure NonAbstractProc(); virtual;
procedure AbstractProc(); virtual; abstract;
end;

TChild = class(TParent)
public
procedure AbstractProc(); override;
end;

TVmt = array[0..0] of pointer;
PVmt = ^TVmt;

procedure TForm1.Button1Click(Sender: TObject);
var
Vmt PVmt;
byte_offset: longword;
begin
Vmt := pointer(TParent);
asm
mov byte_offset, vmtoffset TParent.AbstractProc
end;
if pointer(pointer(TAbstract)^) = Vmt^[byte_offset shr 2] then
ShowMessage("AbstractProc is really abstract!!!");
asm
mov byte_offset, vmtoffset TParent.NonAbstractProc
end;
if pointer(pointer(TAbstract)^) = Vmt^[byte_offset shr 2] then
ShowMessage("NonAbstractProc is only virtual...");
Vmt := pointer(TChild);
asm
mov byte_offset, vmtoffset TChild.AbstractProc
end;
if pointer(pointer(TAbstract)^) = Vmt^[byte_offset shr 2] then
ShowMessage("AbstractProc is already override...");
end;

на мой взгляд достаточно красивое решение :)


 
Толик ©   (2003-07-11 15:32) [12]

Сорри, во втором и третьем if"ах = заменить на <>. А то мессаги на появятся...


 
Юрий Федоров ©   (2003-07-11 15:40) [13]

>>Толик
Вот спасибо, а то я тут мучаюсь, проклиная собственную тупость.
Сейчас попробую


 
Толик ©   (2003-07-11 16:09) [14]

можно даже ещё красивее сделать: занести проверку указателей внутрь TAbstract

type
TAbstract = class(TObject)
protected
procedure AbstractProc(); virtual; abstract;
public
class function Check(const AEntryPoint: pointer): boolean;
end;

TVmt = array[0..0] of pointer;
PVmt = ^TVmt;

class function TAbstract.Check(const AEntryPoint: pointer): boolean;
begin
RESULT := AEntryPoint = pointer(pointer(SELF)^);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
proc_index: longword;
Vmt: PVmt;
begin
Vmt := pointer(TParent);
asm
mov proc_index, vmtoffset TParent.AbstractProc shr 2
end;
if TAbstract.Check(Vmt^[proc_index]) then
ShowMessage("abstract");
end;

Ну вот теперь вроде бы совсем вылизано.


 
Юрий Федоров ©   (2003-07-11 16:13) [15]

Спасибо, с некоторыми изменениями все получилось :-)


 
Юрий Федоров ©   (2003-07-11 17:14) [16]

еще один вопрос.
Можно ли вместо
mov proc_index, vmtoffset TParent.AbstractProc shr 2

написать что-то вроде
type
TParentClass = class of TParent;
...
var ParentClass : TParentClass

...
mov proc_index, vmtoffset ParentClass.AbstractProc shr 2

так как я написал - не компилируется,
Inline assembler syntax error


 
Skier ©   (2003-07-11 17:16) [17]

mov proc_index, vmtoffset TParentClass.AbstractProc shr 2 ?


 
Юрий Федоров ©   (2003-07-11 17:29) [18]

>>Skier © (11.07.03 17:16)
Это я уже туплю :-(
просто как обычно пытался вынести метод в библиотечный модуль, чтобы можно было использовать на все случаи жизни.
Но так видимо не получится.


 
reonid ©   (2003-07-11 17:30) [19]

Юрий Федоров © (11.07.03 17:14)
А какая у тебя версия Дельфи?


 
Юрий Федоров ©   (2003-07-11 17:32) [20]

>>reonid © (11.07.03 17:30)
6


 
Толик ©   (2003-07-11 17:34) [21]

to Юрий Федоров © (11.07.03 17:14)

Не-а нельзя. Дело в том, что смещение в VMT определяется в момент компиляции. А вот что будет лежать в переменной ParentClass компилятор не знает да и знать не может.
Да и хелпы говорят: «This directive needs a fully specified class name with a method name as a parameter, for example,TExample.VirtualMethod.»


 
reonid ©   (2003-07-11 17:46) [22]

Юрий Федоров © (11.07.03 17:29)

А смысл этого какой (даже если б это откомпилилось)
mov proc_index, vmtoffset ParentClass.AbstractProc shr 2 ???

Смещение AbstractProc в VMT одно и то же для всех потомков TParent, и это дало бы тот же самый результат, что и
vmtoffset TParent.AbstractProc


 
Юрий Федоров ©   (2003-07-11 17:59) [23]

>>reonid © (11.07.03 17:46)
Я и говорю - затупил слегка в конце недели :-)


 
reonid ©   (2003-07-11 18:02) [24]

Юрий Федоров © (11.07.03 17:59)
Как я тебя понимаю...
:-)



Страницы: 1 вся ветка

Текущий архив: 2003.07.24;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.022 c
14-78062
Aga
2003-07-05 13:13
2003.07.24
Ура!!


3-77713
boka
2003-06-30 07:35
2003.07.24
Как сохранить файл отчета (*.qrp).


14-78095
Карлсон
2003-07-08 00:35
2003.07.24
что с почтовым ящиком или The Bat! виноват?


1-77963
Micke
2003-07-11 08:30
2003.07.24
Запуск нескольких копий приложения средствами Delphi


3-77734
PlaTinum
2003-06-29 23:00
2003.07.24
Клиент/Сервер