Подскажите синтаксис

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Ответить
Alex333
новенький
Сообщения: 32
Зарегистрирован: 21.08.2011 19:14:28

Подскажите синтаксис

Сообщение Alex333 »

Есть некая функция, в которую передается указатель на метод (ну, скажем, протоколирование результатов), описанный примерно так:

Код: Выделить всё

TProt = procedure (const sProt:String) of object;

Сам метод выглядит примерно как - то так:

Код: Выделить всё

procedure TFMyForm.Prot(const s:String);
begin
  MyProt.Lines.Add(s);
end;

Функция (из формы) вызывается примерно так:

Код: Выделить всё

MyFunc(@Prot);

Ну а в самой функции что-то такое:

Код: Выделить всё

function MyFunc(FMyProt:TProt):Boolean;
begin
.........
   if Assigned(FMyProt) then
       FMyProt('Что-то-там...');
.........
end;

Вопрос: а как мне подсунуть этой функции (не изменяя её саму) в качестве параметра не указатель на метод формы, а указатель на обычную процедуру, не являющуюся методом? Возможно такое? И как должна быть описана такая процедура?
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

Alex333
новенький
Сообщения: 32
Зарегистрирован: 21.08.2011 19:14:28

Сообщение Alex333 »

Чего-то не даёт мне компилятор такое сделать, как по ссылке. Ругается.
Ну, может он и прав по-своему. Язык-то не зря сильно типизированный.
Сделал в итоге простейший класс, а свою процедуру сделал его методом. И передаю указатель на этот метод.
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

Alex333 всё прекрасно работает и по сей день. читайте тему до конца.

Добавлено спустя 2 минуты 6 секунд:
приведите "ругань"...
Alex333
новенький
Сообщения: 32
Зарегистрирован: 21.08.2011 19:14:28

Сообщение Alex333 »

Код: Выделить всё

procedure TMyClass.MyProt(const sProt:String);
begin
end;

procedure proc1(const sProt:String;Sender:TObject);
begin
end;

//WrkDir(Utf8ToAnsi(s),FDObj,@MyClass.MyProt);  //Так нормально
WrkDir(Utf8ToAnsi(s),FDObj,@proc1);  //А так ругается


Ругань вот такая:

Код: Выделить всё

SetDates.lpr(53,42) Error: Incompatible type for arg no. 3: Got "<address of procedure(const AnsiString,TObject);Register>", expected "<procedure variable type of procedure(const AnsiString) of object;Register>"
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

Код: Выделить всё

procedure proc1(Sender:TObject; Const sProt:String);
Alex333
новенький
Сообщения: 32
Зарегистрирован: 21.08.2011 19:14:28

Сообщение Alex333 »

Исправил, но легче не стало:

SetDates.lpr(52,42) Error: Incompatible type for arg no. 3: Got "<address of procedure(TObject,const AnsiString);Register>", expected "<procedure variable type of procedure(const AnsiString) of object;Register>"
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

Код: Выделить всё

procedure proc1(self:TObject; Const sProt:String);
....

var
  m: TMethod;
...
  m.Code:=@Proc1;
  m.Data:=nil;

  MyFunc(TProt(m));
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

Код: Выделить всё


Unit Unit1;

{$mode objfpc}{$H+}

Interface

Uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs;

Type TMyEvent = Procedure(Sender: TObject; Const aString: String) Of Object;

Type

  { TForm1 }

  TForm1 = Class(TForm)
  Private
    FOnMyEvent: TMyEvent;
    { private declarations }
  Public
    { public declarations }
    Procedure HelloWorld(Const aMessage: String);
    Property OnMyEvent : TMyEvent Read FOnMyEvent Write FOnMyEvent;
    constructor Create(TheOwner: TComponent); override;
  End;

Var
  Form1: TForm1;

Implementation

Procedure MyClick(Self, Sender: TObject);
Begin
  TForm1(Self).HelloWorld('Hello world');
End;

Procedure MyEvent(Self, Sender : TObject; Const aString: String);
Begin
  ShowMessage(aString);
End;

{$R *.lfm}

{ TForm1 }

Procedure TForm1.HelloWorld(Const aMessage: String);
Begin
  If Assigned(FOnMyEvent) Then FOnMyEvent(Self, aMessage);
  Caption := 'Hello World'
End;

Constructor TForm1.Create(TheOwner: TComponent);
Var
  aMyEvent, aClick: TMethod;
Begin
  Inherited Create(TheOwner);
  aMyEvent.Data := nil;
  aMyEvent.Code := @MyEvent;
  OnMyEvent := TMyEvent(aMyEvent);

  aClick.Data := Self;
  aClick.Code := @MyClick;
  OnClick := TNotifyEvent(aClick);
End;

End.

^_^
Alex333
новенький
Сообщения: 32
Зарегистрирован: 21.08.2011 19:14:28

Сообщение Alex333 »

Код: Выделить всё

var
  m: TMethod;
...
  m.Code:=@Proc1;
  m.Data:=nil;
  MyFunc(TProt(m));


Спасибо - это работает. Большой практической надобности уже не было, но любопытно же. Т.е. что же получается - указатель на метод - это на самом деле указатель на запись вот такого вида?
TMethod = record
Code, Data : Pointer;
end;

Или же в стек копируется сама запись, а не указатель? (я просто не знаю, как происходит приведение типа TProt(m) )

Добавлено спустя 5 часов 51 минуту 55 секунд:
Да, посмотрел в ассемблере - в стек копируется именно запись, т.е. 2 указателя, содержащиеся в ней (правда, в FP я ассемблера что-то не понимаю - непривычный, но в Delphi это выглядит так:)

Код: Выделить всё

;m.code:=@proc1
mov    [ebp-$24],$004537e0   
;m.data:=Nil
xor   eax,eax         
mov   [ebp-$20],eax
;WrkDir(TMyProt(m))
push   dword ptr [ebp-$20]
push   dword ptr [ebp-$24]
call   WrkDir

т.е. обычным адресом процедуры это не заменишь, хоть какие параметры внутри напиши.
Аватара пользователя
AlexVinS
новенький
Сообщения: 95
Зарегистрирован: 27.01.2009 00:18:01

Сообщение AlexVinS »

Alex333 писал(а):
Спасибо - это работает. Большой практической надобности уже не было, но любопытно же. Т.е. что же получается - указатель на метод - это на самом деле указатель на запись вот такого вида?
TMethod = record
Code, Data : Pointer;
end;

Или же в стек копируется сама запись, а не указатель? (я просто не знаю, как происходит приведение типа TProt(m) )


Сама запись.
Ответить