Форум: "Основная";
Текущий архив: 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.009 c