В чем разница @Object vs Pointer (Object)?

Я тестировал следующий код:

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.

Поэтому, если я запустил этот код с помощью методов TObject и передал указатель (PersonB) PersonB в PersonA и вызвал Speak, PersonB.Speak будет выполнен.

Однако, если я удалю виртуальную директиву в обоих методах и снова запустил, Delphi выполнит метод PersonA как статический, потому что его адрес будет скомпилирован непосредственно в код в том месте, где он был вызван.

Итак, когда оба метода были объявлены как виртуальные, и я изменил код:

PersonA: = @ObjectB (PersonB) ==> PersonA: = @PersonB

Я попал в нарушение доступа. Я думаю, что в первом случае это был виртуальный указатель, но в этом случае я запутался в использовании @.

delphi,

2

Ответов: 3


6 ов принято

Переменная, тип которой нисходит, на самом деле является указателем на экземпляр.Address Value +-----------------+ 12345600 | Obj variable | 45680000 +-----------------+ | v +-----------------+ 45680000 | instance | | | | | +-----------------+

Так же Objявляется указателем на экземпляр. Но @Objэто адрес указателя на экземпляр. То есть есть дополнительный уровень косвенности.

FWIW оба этих параметра не имеют смысла и не принесут ничего полезного.

Что касается различного поведения при удалении virtualдирективы, виртуальный метод отправляется с использованием типа среды выполнения экземпляра, то не виртуальный метод отправляется с использованием типа времени компиляции переменной экземпляра. Тот факт, что код работает вообще, связан с двумя несвязанными классами, имеющими совместимые VMT. Но это всего лишь шанс детализации реализации.


6

Давайте сделаем простую диаграмму (адреса составлены):

Pointer

@Obj = Pointer($12345600)является переменной. Это ссылка на объект, что означает, что на самом деле это указатель на экземпляр.

Если вы берете Pointer, вы берете адрес переменной . Его тип есть Pointer.

Так ты и получишь Pointer(Obj).

Если вы выбрали Pointerзначение Pointeras Pointer(Obj) = Pointer($45680000), вы получите адрес экземпляра, на который указывает переменная. Его тип Pointerтоже.

Так ты и получишь .if @Obj = Obj then Writeln('Same') else Writeln('Different'); if Pointer(Obj) = Obj then Writeln('Same') else Writeln('Different');

Вы можете даже проверить это:

Different
Same

и вы должны получить:

Object

РЕДАКТИРОВАТЬ

Я изменил Objк Obj, потому что objectэто зарезервированное слово в Delphi.


Дополнительная информация в моей статье о указателях. Адресаторы .


0

Pointer(Object)является литой тип, @Objectпринимает адрес объекта. Другими словами, @Object<> Pointer(Object). Когда вы используете Pointer(Object), вы не получаете указатель на Object, вы получаете исходное значение указателя.

Дельфы,
Похожие вопросы