See also Procedure Bound To Method Without RTTI Hack
Ever want to use a regular procedure when a procedure is required to be 'of object'?
I'm not sure if this is safe to do, but using some tricks we can turn a regular procedure type into being compatible with a procedure method inside a class, i.e a procedure of object bound to a plain procedure.
Note the {$M+} switch is used to turn on 'type information', otherwise the program below won't execute the Tx.P() method.
program test; {$mode objfpc} {$H+}{$M+}
type
Tx = class
// published
procedure p;
end;
procedure Tx.p;
begin
writeln('proc test');
end;
var
x: Tx;
p: procedure; // normally we would need procedure OF OBJECT
begin
x:= Tx.create;
pointer(p):= x.MethodAddress('p');
if assigned(p) then
p() // call a regular procedure and not 'of object'? Magic.
else
writeln('unassigned');
x.free;
readln;
end.
And now for the real trickery:
program test29; {$mode objfpc} {$H+}{$M+}
type
Tx = class
procedure p;
procedure test(i: integer);
private
s: string;
end;
procedure Tx.p;
begin
writeln('proc test 1');
// how does this method know about SELF? take a guess
self.s:= 'hello ';
self.s:= 'hello ' + s + s;
writeln(self.s);
end;
procedure Tx.test(i: integer);
begin
writeln('proc test 2');
// how does this method know about SELF? take a guess
self.s:= 'hello ';
self.s:= 'hello ' + s + s + ' see number: ';
writeln(self.s, i);
end;
var
x: Tx;
// normally we would need procedure OF OBJECT
p: procedure(fakeself: pointer);
// the pointer acts as our object SELF
test: procedure(fakeself: pointer; i: integer);
// alternatively: don't have to use a pointer.. we can use Tx
// test: procedure(fakeself: Tx; i: integer);
begin
x:= Tx.create;
// bind regular procedures to an object method
pointer(p):= x.MethodAddress('p');
pointer(test):= x.MethodAddress('test');
if assigned(p) then
begin
// now launch the procedures
p(pointer(x));
test(pointer(x), 600); { pointer is our hidden SELF param }
end else
writeln('unassigned');
x.free;
readln;
end.
Points/theories to think about and question:
- a regular procedure can be faked/binded to an object method
- regular procedures have benefits, such as exportable from DLL, or simplicity when an object/class is not needed.
- how to obtain object instance if we were playing with DLL? Get it/export it using something like GetObjInstance()
- VMT/RTTI (as and is) issues.. think about problems there
|