TTestClass = class
content: Integer;
end;
TTest = class
public
class procedure TestProc<T: class>(obj: T);
end;
class procedure TTest.TestProc<T>(obj: T);
var
p: Pointer;
begin
p := Pointer(obj);
p := @obj;
end;
Here, the two different ways of getting a pointer to an object give different results. RTTI functions take the first method, but it only works for classes. So how can I get an instance of Pointer
for any generic variable (ie replace T: class
by just T
) ? And why is the actual pointer different ?
Pointer(obj)
type-casts the value of obj
into a Pointer
, whereas @obj
gives you the memory address of obj
itself. Hence you will always get 2 different addresses.
A class object is a reference type, it is passed around by pointer.
When you have the obj
parameter constrained with the class
Generic attribute, you are forcing obj
to be an object pointer. So its value will point at the object, and @obj
will be the address of the parameter itself, not the object it is pointing at.
When obj
is not constrained then it can be any type, it’s not guaranteed to be a pointer at all. If it is a value type (like an integer, etc) instead of a reference type (like an object), you will have to pass it in as a var
parameter in order to use @obj
to get the address of the caller’s original variable.
6
The first method – Pointer(obj)
– is just a cast, and “does” nothing. It just takes the variable obj
and looks at it as if it were a pointer. This happens to work for classes, because such variables actually do hold pointers.
The second method – @obj
– actually does something: it creates a pointer to the variable. This works for all types of variables.
A problem with the second method might be that the parameter (obj
) is passed by value, not by reference, so @obj
gives you a pointer to the local variable obj
, and not to the original variable that was passed as argument to TestProc. To make @obj
point to the original variable passed as argument to TTestProc
, add the var
keyword:
class procedure TestProc<T>(var obj: T);
4