Страница 1 из 1
процедурные переменные
Добавлено: 20.01.2010 13:50:58
AlexP
У меня есть обьект, который работает с процедурной переменной.
Только иногда приходится работать не только с обычными функциями, а еще с функциями, которые являются методом какого-нибудь обьекта.
Но такая функция, хоть и имеет такой же список параметров, является другим типом процедурной переменной, т.е. получается, что для того, чтобы работать ещё и с такими функциями, мне надо написать еще один такой же точно обьект, только для работы с процедурной переменной этого типа. Т.е. абсолютно одинаковый код увеличивается в два раза. Это можно как-нибудь обойти?
Re: процедурные переменные
Добавлено: 20.01.2010 13:59:32
AbakAngelSoft
Даже если метод имеет тот-же список параметров - у него есть первый скрытый параметер Self. И ссылка на метод хранит помимо адреса процедуры адрес объекта к которому относится процедура для того что-бы при вызове восстановить этот параметер!
Добавлено спустя 4 минуты 49 секунд:
как вариант можно в процедурные типы добавить фиктивный параметер типа pointer при сохранении приводить процедурную переменную к ссылке на метод.
Met: TMethod;
Met.Code := Pointer(<процедурная переменная>)
Met.Data := nil;
А вызывать так как вызывается метод в процедуре игнорируя первый параметер.
Re: процедурные переменные
Добавлено: 20.01.2010 16:03:20
Astralis
насчет вызова немного уточню: такие методы не должны использовать в своем теле Self
если же они в своем теле используют Self, то его явно нужно передавать
в арихитектуре Intel при соглашении вызова thiscall можно явно передать параметр self
Код: Выделить всё
asm
MOV ECX, NeedSelf
end;
ReturnValue:=ExecuteFunction(<params list>);
class-методы полностью совместими с обычными функциями
Re: процедурные переменные
Добавлено: 20.01.2010 21:28:37
Mr.Smart
AstralisА вот и нет! Все функции класса имеют скрытый первый параметр, который и является указателем на self

Re: процедурные переменные
Добавлено: 20.01.2010 22:07:51
Sergei I. Gorelkin
Эта цитата из документации C/C++ вообще не имеет никакого отношения к FPC.
Начиная с того, что тип вызова thiscall отсутствует, первый параметр передается не в ecx, а в eax (при типе вызова register, иначе в стеке), ассемблерная вставка перед вызовом ф-ции никакого эффекта иметь не будет, т.к. вызов разместит все параметры на нужных местах.
Re: процедурные переменные
Добавлено: 21.01.2010 00:17:07
Astralis
Приятно удивлен, что в FPC с классами все гораздо и внятнее
в этом плане вызов метода как функции легок и прост
Код: Выделить всё
type
TA = procedure(<param list>) of object;
TB = procedure(Self: TObject; <param list>);
var A: TA; B: TB;
...
B:=TB(TMethod(A).Code);
B(TMethod(A).Data,<param list>);
что касается соглашения thiscall - то его нет в FPC, но оно может неявно возникнуть, когда происходит импорт классов из dll, созданных в C++ (например, UNO). в этом случае код привенный в предыдущем сообщении, вполне работоспособен (при условии, что функция определена как stdcall), разве что в C++ конструктор не выделяет память под объект, а класс-методы используют соглашение cdecl.
Re: процедурные переменные
Добавлено: 21.01.2010 01:08:44
Sergei I. Gorelkin
Когда вызываемая функция определена как stdcall или cdecl, то все параметры передаются в стеке (включая скрытый self) и нет ну просто никакой необходимости что-то писать в регистры с помощью ассемблерных вставок. Да, этот пример работоспособен, потому что регистр ecx в таком месте можно перезаписать чаще всего без последствий. Но зачем?
Re: процедурные переменные
Добавлено: 21.01.2010 09:54:48
AbakAngelSoft
Я и говорил что Self в процедуре просто не использовать.
Только удобнее вызывать все как методы:
Код: Выделить всё
type
TA = procedure(<param list>) of object;
TB = procedure(Self: TObject; <param list>);
TCaller = class(...)
private
FMeth: TA;
public
property Meth: TA read FMeth write FMeth;
property Proc: TB read GetProc write SetProc;
end;
function TCaller.GetProc: TB;
begin
Result := TB(TMethod(FMeth).Code);
end;
procedure TCaller.SetProc(AValue: TB);
begin
TMethod(FMeth).Code := Pointer(AValue);
TMethod(FMeth).Data := nil;
end;
И вызываем
Не взирая на то - метод там или процедура
Re: процедурные переменные
Добавлено: 22.02.2010 19:18:47
Astralis
thiscall в FPC в явном виде не используется, но он неявно возникает при импорте классов, написанных на c++, например при работе с OpenOffice. Импорт отдельных методов из dll-файла есть более гибкое решение, чем использование ключевого слова cppclass.
Наример, есть класс написанный на c++
Код: Выделить всё
class __declspec(dllexport) Foo
{
public:
Foo()
{
i = 0;
cout<<"create"<<endl;
}
~Foo()
{
cout<<"death"<<endl;
}
void inc()
{
i++;
cout<<"increment"<<endl;
}
void print()
{
cout<<"value is "<<i<<endl;
}
private:
int i;
};
С помощью утилиты dumpbin легко получить таблицу экспортируемых методов.
Код: Выделить всё
0 00001AF0 ??0Foo@@QAE@XZ public: __thiscall Foo::Foo(void)
1 00001B20 ??1Foo@@QAE@XZ public: __thiscall Foo::~Foo(void)
2 000013D0 ??4Foo@@QAEAAV0@ABV0@@Z public: class Foo & __thiscall Foo::operator=(class Foo const &)
3 00001B60 ?inc@Foo@@QAEXXZ public: void __thiscall Foo::inc(void)
4 00001BA0 ?print@Foo@@QAEXXZ public: void __thiscall Foo::print(void)
Соответственно эти функции импортируются в программе на fpc:
Код: Выделить всё
procedure FooCreate;stdcall;external 'wins.dll' name '??0Foo@@QAE@XZ';
procedure FooDestroy;stdcall;external 'wins.dll' name '??1Foo@@QAE@XZ';
procedure FooInc;stdcall;external 'wins.dll' name '?inc@Foo@@QAEXXZ';
procedure FooPrint;stdcall;external 'wins.dll' name '?print@Foo@@QAEXXZ';
c++ при вызове методов использует thiscall, соответственно это тот же stdcall но дополнительно в регистре ECX передается узаказтель на объект (this). Соответственно выполнение программы на fpc выглядит следующим образом:
Код: Выделить всё
GetMem(this,size);
asm
MOV ECX, this
end;
FooCreate;
asm
MOV ECX, this
end;
FooInc;
asm
MOV ECX, this
end;
FooInc;
asm
MOV ECX, this
end;
FooPrint;
asm
MOV ECX, this
end;
FooDestroy;
FreeMem(this);
результат:
Re: процедурные переменные
Добавлено: 22.02.2010 19:59:11
Sergei I. Gorelkin
Эта конструкция рассыплется к чертовой бабушке при наличии у функций аргументов.
Re: процедурные переменные
Добавлено: 13.04.2010 14:52:02
sign
У меня по теме вопрос.
Пытаюсь прикрутить библиотеку DeCAL и встретил такое.
Код: Выделить всё
...
DComparator = function (const obj1, obj2 : DObject) : Integer of object;
...
protected
comparator : DComparator;
...
function DObjectComparator(const obj1, obj2 : DObject) : Integer;
...
constructor DContainer.create;
begin
comparator := DObjectComparator;
end;
И вот на последнем присваивании Лазарь ругается: "Error: Wrong number of parameters specified for call to "DObjectComparator"/
Как будто Лазарус определяет, что тут идет вызов фукции, а не присвоение.
Что тут не так и как можно исправить?
Re: процедурные переменные
Добавлено: 13.04.2010 15:00:39
Mr.Smart
Re: процедурные переменные
Добавлено: 13.04.2010 15:29:47
sign
Спасибо.