Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference of @Object vs Pointer( Object )?

Tags:

delphi

I was testing this following code:

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.

So if i run this code with methods as virtual and pass a pointer of PersonB to PersonA and call the Speak, PersonB.Speak is executed.

However, if i delete the virtual directive in both methods and run again then delphi executes the method of PersonA as static, cause it's adress will be compiled directly into the code at the place it was called.

So, when both methods were declared as virtual and i changed the code:

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

I got into a access violation. I think was doing in the first case a pointer of pointer but i've gotten confuse with the usage of @ in that case.

like image 393
Wellington Silva Ribeiro Avatar asked Dec 07 '22 14:12

Wellington Silva Ribeiro


2 Answers

A variable whose type descends from TObject is actually a pointer to the instance.

So Pointer(PersonB) is also pointer to the instance. But @ObjectB is the address of a pointer to the instance. That is there is an extra level of indirection.

FWIW both of these two options are meaningless and will not lead anywhere useful.

As for the different behaviour when you remove the virtual directive, a virtual method is dispatched using the runtime type of the instance, a non-virtual method is dispatched using the compile time type of the instance variable. The fact that the code runs at all is due to the two unrelated classes having compatible VMTs. But that's just a chance of implementation detail.

like image 156
David Heffernan Avatar answered Jan 15 '23 02:01

David Heffernan


Let's make a simple diagram (addresses are made up):

Address                        Value
          +-----------------+
12345600  |  Obj variable   |  45680000
          +-----------------+
                   |
                   v
          +-----------------+
45680000  |     instance    |  
          |                 |
          |                 |
          +-----------------+

Obj is a variable. It is an object reference, which means it is actually a pointer to the instance.

If you take @Obj, you take the address of the variable. Its type is Pointer.

So you get @Obj = Pointer($12345600).

If you cast Obj to Pointer as Pointer(Obj), you get the address of the instance to which the variable points. Its type is Pointer too.

So you get Pointer(Obj) = Pointer($45680000).

You can even test this:

if @Obj = Obj then
  Writeln('Same')
else
  Writeln('Different');
if Pointer(Obj) = Obj then
  Writeln('Same')
else
  Writeln('Different');

and you should get:

Different
Same

EDIT

I changed Object to Obj, because object is a reserved word, in Delphi.


More info in my article on pointers: Addressing pointers.

like image 22
Rudy Velthuis Avatar answered Jan 15 '23 04:01

Rudy Velthuis