I am asking to advance my understanding of Self.
Please consider the following:
type
PTestObject = ^TTestObject;
TTestObject = class(TObject)
private
FCaption : String;
public
procedure MakeThePointer;
property Caption : String read FCaption write FCaption;
end;
TForm4 = class(TForm)
ButtonFirst: TButton;
ButtonSecond: TButton;
ButtonThird: TButton;
procedure ButtonFirstClick(Sender: TObject);
procedure ButtonSecondClick(Sender: TObject);
procedure ButtonThirdClick(Sender: TObject);
private
public
end;
var
Form4: TForm4;
PointerOfTest : PTestObject;
TestObj : TTestObject;
implementation
{$R *.dfm}
procedure TTestObject.MakeThePointer;
begin
PointerOfTest := @Self;
end;
procedure TForm4.ButtonFirstClick(Sender: TObject);
begin
TestObj := TTestObject.Create;
TestObj.Caption := 'Hello';
TestObj.MakeThePointer;
end;
procedure TForm4.ButtonSecondClick(Sender: TObject);
begin
TestObj.MakeThePointer;
ShowMessage(PointerOfTest^.Caption);
end;
procedure TForm4.ButtonThirdClick(Sender: TObject);
begin
// TestObj.MakeThePointer; - Because I do not do this I get Access Violation
ShowMessage(PointerOfTest^.Caption);
end;
The idea is to create a pointer to TestObj's Self
and then later access it again. If I call MakeThePointer
in the same Click event (ButtonSecondClick
) where I access that pointer it works fine. If I do not call MakeThePointer
before accessing the pointer (ButtonThirdClick
) then it seems that TestObj's Self
does not exist in such a way that the previously created pointer is valid and I get an Access Violation.
Please correct me if I am wrong but I assume that Self is a variable local to each of the object's methods. Thus it will have scope only for each of that methods separately?
Now consider this... If that is the case then why does the following work if ButtonFirst is clicked, then ButtonSecond? It seems that the Self variable has landed on the same address thus allowing the following to work. May I assume that the Self variable will always be on the same address or will it change?
type
TFormOther = class(TForm)
ButtonFirst: TButton;
ButtonSecond: TButton;
procedure ButtonFirstClick(Sender: TObject);
procedure ButtonSecondClick(Sender: TObject);
private
public
procedure MakeThePointer;
procedure SetTheCaption;
end;
var
FormOther: TFormOther;
PointerOfForm : ^TForm;
implementation
{$R *.dfm}
procedure TFormOther.MakeThePointer;
begin
PointerOfForm := @Self;
end;
procedure TFormOther.SetTheCaption;
begin
PointerOfForm^.Caption := 'Hello';
end;
procedure TFormOther.ButtonFirstClick(Sender: TObject);
begin
MakeThePointer;
end;
procedure TFormOther.ButtonSecondClick(Sender: TObject);
begin
SetTheCaption;
end;
What is the scope of Self?
In a method Self
is best thought of as a local variable. Its address, @Self
, is therefore valid until the method returns.
This explains why your code fails. Your code dereferences the pointer after the method has returned, by which point the pointer is not valid.
May I assume that the Self variable will always be on the same address?
No you may not.
I think your problems start here:
type
PTestObject = ^TTestObject;
Because TTestObject
is a class, a variable of type TTestObject
, such as your Self
, is a reference. A reference is a fancy name for a pointer. In this case, your Self
, inside methods of TTestObject
is a pointer to the instance.
So use TTestObject
instead of ^TTestObject
and your problems dissolve.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With