@Object vs Pointer(Object)有什么区别?

Wel*_*iro 2 delphi

我正在测试以下代码:

type
  TPersonA = class
    public
      procedure Speak;virtual;
  end;

  TPersonB = class
    public
      procedure Speak;virtual;
  end;
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var PersonA: TPersonA;
    PersonB : TPersonB;
begin
  PersonA := TPersonA.Create;
  PersonB := TPersonB.Create;

  PersonA := Pointer( PersonB );
  PersonA.Speak;
end;

procedure TPersonA.Speak;
begin
  ShowMessage('Hello');
end;


procedure TPersonB.Speak;
begin
  ShowMessage('Hello again');
end;

end.
Run Code Online (Sandbox Code Playgroud)

因此,如果我使用方法作为虚函数运行此代码并将PersonB的指针传递给PersonA并调用Speak,则执行PersonB.Speak.

但是,如果我在两个方法中删除虚拟指令并再次运行,那么delphi将PersonA的方法作为静态执行,因为它的地址将被直接编译到它被调用的地方的代码中.

因此,当两个方法都声明为虚拟并且我更改了代码时:

PersonA:=指针(PersonB)==> PersonA:= @PersonB

我遇到了访问冲突.我认为在第一种情况下是指针指针,但在这种情况下,我已经混淆了@的用法.

Dav*_*nan 6

类型来自的变量TObject实际上是指向实例的指针.

所以Pointer(PersonB)也是指向实例的指针.但是@ObjectB指向实例的指针的地址.这是一个额外的间接水平.

FWIW这两个选项都没有意义,并且不会带来任何有用的选择.

对于删除virtual指令时的不同行为,使用实例的运行时类型调度虚方法,使用实例变量的编译时类型调度非虚方法.代码运行的事实是由于两个不相关的类具有兼容的VMT.但这只是实施细节的一个机会.


Rud*_*uis 6

让我们制作一个简单的图表(地址组成):

Address                        Value
          +-----------------+
12345600  |  Obj variable   |  45680000
          +-----------------+
                   |
                   v
          +-----------------+
45680000  |     instance    |  
          |                 |
          |                 |
          +-----------------+
Run Code Online (Sandbox Code Playgroud)

Obj是一个变量.它是一个对象引用,这意味着它实际上是一个指向实例的指针.

如果你采取@Obj,你采取变量地址.它的类型是Pointer.

所以你得到了@Obj = Pointer($12345600).

如果Obj转换Pointer为as Pointer(Obj),则获取变量指向的实例地址.它的类型Pointer也是.

所以你得到了Pointer(Obj) = Pointer($45680000).

你甚至可以测试这个:

if @Obj = Obj then
  Writeln('Same')
else
  Writeln('Different');
if Pointer(Obj) = Obj then
  Writeln('Same')
else
  Writeln('Different');
Run Code Online (Sandbox Code Playgroud)

你应该得到:

Different
Same
Run Code Online (Sandbox Code Playgroud)

编辑

我换ObjectObj,因为object是保留字,在Delphi中.


关于指针的文章中的更多信息:寻址指针.