Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2003.07.24;
Скачать: [xml.tar.bz2];

Вниз

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

 
Юрий Федоров   (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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.01 c
3-77718
Zigs
2003-06-30 12:06
2003.07.24
Проблема с точностью значения на клиенте ...


14-78051
Soft
2003-07-06 03:01
2003.07.24
Мы убьем машинами Вселенную


3-77760
alois
2003-07-01 20:55
2003.07.24
Разнесение строки из Memo по полям


14-78152
vidiv
2003-07-02 13:50
2003.07.24
Зачем в первой цивилизации строить ...


1-77873
Seldon
2003-07-13 19:20
2003.07.24
TActionManager





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский