我一直认为Delphi中的对象实际上是对内存位置的引用,而我认为这些内存存储为指针变量。
现在,我想从一个物体制作一个TValue。考虑一下:
TValue.Make(AObject, TypeInfo(TMyObject), val);
其中val: TValue
。这不行。实际上,后续使用val
会导致访问冲突。但是,如果我们使用address-of运算符,就像这样:
TValue.Make(@AObject, TypeInfo(TMyObject), val);
一切都很好。对我来说,这是出乎意料的,因为我认为AObject(引擎盖下)实际上是一个指针。我错了,或者这是TValue.Make方法的怪癖?有人可以赐教我吗?
答案 0 :(得分:9)
procedure Foo;
var
I: Integer; // value type
O: TObject; // reference type
begin
@I; // Get a pointer to I
O := TObject.Create;
@O; // Get a pointer to the memory "behind" the reference O
end;
通常这并不重要,因为编译器知道何时取消引用,何时不知道。
在TValue.Make
的情况下,该函数采用指针。
Make(O...
时,编译器将硬引用指针(指向堆栈)。Make(@O...
时,编译器将首先取消引用,然后创建指向堆上位置的指针。所以你必须在这种情况下给编译器一个提示,因为它不知道TValue.Make
期望哪种指针。
答案 1 :(得分:2)
传递给TValue.Make的ABuffer参数是指向要存储在TValue中的值的指针。类型本身是否是指针类型并不重要。因此,即使AObject本身也是指针,您也必须将引用传递给AObject。
在您发布的示例中,我更倾向于使用TValue.From< T>方法:
val := TValue.From<TMyObject>(AObject);
如果在编译时不知道typeinfo,则必须使用TValue.Make - 否则TValue.From&lt; T&gt;更容易使用。
答案 2 :(得分:1)
在您的示例中,AObject是对对象的引用,而不是对象本身。这是在Delphi中声明对象引用的方法,而不是必须显式添加对象的引用或指针的其他语言。
所以 AObject 或 @AObject 应该在你的情况下工作相同,但是当TValue.Make()
在第一个参数中取一个指向缓冲区的指针时,你应该向该函数提供Addr(AObject)
或@AObject
。