Delphi自指针用法

6

我需要在类实例内部获取指向该实例的指针。我不能直接使用"Self",因为我需要将指针存储以备将来使用。我尝试了下面的代码:

type
    TTest = class(TObject)
    public
        class function getClassPointer: Pointer;
        function getSelfPointer: Pointer;
    end;

class function TTest.getClassPointer: Pointer;
begin
    Result := Pointer(Self);
end;

function TTest.getSelfPointer: Pointer;
begin
    Result := Pointer(Self);
end;

两个结果都是错误的 - 这段代码:

test := TTest.Create;
Writeln('Actual object address: ', IntToHex(Integer(@test), 8));
Writeln('Class "Self" value: ', IntToHex(Integer(test.getClassPointer()), 8));
Writeln('Object "Self" value: ', IntToHex(Integer(test.getSelfPointer()), 8));

返回:

Actual object address:    00416E6C
Class "Self" value:       0040E55C
Object "Self" value:      01EE0D10

请帮我理解,“Self”值是什么?“Self”是指向该类实例的指针吗?如何使用此指针在对象外部进行将来的使用?如何从该值获取适当的指针?

2个回答

13

您正在尝试比较三个完全不同的实体。

@test返回变量test的地址,而不是它指向的对象实例。

test.getClassPointer()返回类元数据的地址。类元数据是编译器生成的常量数据结构,在运行时可以找到虚拟方法表、运行时类型信息表等。所有类的实例共享相同的类元数据结构。类元数据的指针是对象实例的类型标识——这就是对象在运行时知道自己是什么类型的方式。

test.getSelfPointer()给出了内存中对象实例的实际地址。两个不同创建的对象实例将具有不同的实例地址。test.getSelfPointer()将等于test实例变量的内容:Pointer(test)

例如(伪代码,未经测试):

type TTest = class
     end;

var test1: TTest;
    test2: TTest;

begin
  test1 = TTest.Create;  // allocates memory from the global heap, stores pointer
  test2 = test1;         // copies the pointer to the object into test2 variable
  writeln("Test1 variable points to: ", IntToHex(Integer(Pointer(test1))));
  writeln("Test2 variable points to: ", IntToHex(Integer(Pointer(test1))));
end.

1
谢谢!现在我明白如何使用它了! TTest(Pointer(test))或TTest(test.getSelfPointer())-这就是我需要的=) - soar
5
这些对于Delphi来说是非常奇怪的结构。你确定你没有让事情过于复杂了吗?你的foo = TTest(Pointer(test))与仅仅说foo = test是一样的。在Delphi中,每个对象实例变量实际上都是一个指针。指针性质就在表面下。 - dthorpe
1
此外,getClassPointer与内置的ClassType方法相同。 - Rob Kennedy
我的问题只是一个例子,实际上我使用了结构体,其中对象作为字段放置在另一个对象中,并且其中没有"test"。现在我可以将适当的指针传递给它。谢谢大家! - soar

0
在你的代码片段中,test 已经是对实例的引用,因此你应该尝试。
Writeln('Actual object address: ', IntToHex(Integer(Pointer(test)), 8));

你可能不需要任何getSelfPointer方法。如果你想要一个对test已经引用的对象实例的第二个引用,请写:

var
  SecondReferenceToTest: TTest;
SecondReferenceToTest := test;

为了看到这个,请尝试类似以下的内容:

type
  TTest = class(TObject)
  public
    Name: string;
  end;

procedure TestProc;
var
  test, SecondReferenceToTest: TTest;
begin
  test := TTest.Create;
  try
    test.Name := 'Named via "test" reference';
    SecondReferenceToTest := test;
    ShowMessage(SecondReferenceToTest.Name);
  finally
    test.Free;
  end;
end;

这种方式可以在对象外获取引用,但我该怎么做才能从该对象的方法中返回有效的指针?就像我的示例中一样。 - soar
@Soara,如果你要在对象上调用一个方法,那么你已经有了对该对象的引用。对象本身没有任何“特殊”的访问权限。在实例方法中,Self是对对象的引用,与调用者必须已经拥有的引用相同,如果他们正在调用对象上的方法。在类方法中,Self是对类的引用,而不是类的任何实例。 - Rob Kennedy
我的问题只是一个示例,实际上我使用的是结构体,其中对象作为字段放置在其他对象中,并且其中没有“test”。现在我可以传递适当的指针给它。谢谢大家! - soar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接