Coming from a C++ background, I understand classes, pointers and memory addresses reasonably well. However, with Delphi, I am finding myself confused.
I understand that when you declare a variable of a particular type of class in the var
section of a function/procedure, what you're really declaring is a POINTER to that class. E.g., the following Delphi and C++ are roughly equivalent, both allocating the amount of memory required for the MyObject
class on the heap.
// Delphi
procedure Blah.Something();
var
o: MyObject;
begin
o := MyObject.Create;
o.Free;
end;
// C++
void Blah::Something()
{
MyObject *o = new MyObject();
delete o;
}
In C++, using pointers (and references) allows the use of virtual methods for class hierarchies. However, if you don't have class hierarchies, you can declare a variable on the stack (which executes faster). If you need to pass the variable around as a pointer, you can simply get its address with the &
operator.
// C++
void Blah::Something()
{
// This is allocated on the stack.
MyObject o;
// This address of this stack-allocated object is being used.
doSomethingWithAnOhPointer(&o);
}
At this stage, I have a few questions regarding Delphi's use of classes and pointers.
o := MyObject.Create
uses heap-allocation in Delphi, how do you allocate an object on the stack?o: MyObject
is really a pointer, then why is the ^
pointer symbol never used. Is this a "convenience" idiom in Delphi?How can you get the address of the actual MyObject
located on the heap? I have tried: the following.
WriteLogLine('Address of object: ' + Format('%p', [@o])); // This prints the address of the 'o' pointer.
WriteLogLine('Address of object: ' + Format('%p', [o])); // This causes the program to crash.
It's possible that I have misunderstood some Delphi fundamentals, but I have not found anyone (physically or on the Internet) who can explain the above to my satisfaction.
EDIT
Given that Delphi typically only allocates memory on the heap, then:
Why does the assignment ("THIS ASSIGNMENT") not compile?
procedure Blah.Something();
var
o1: MyObject;
o2: MyObject;
oP: ^MyObject;
begin
o1 := MyObject.Create;
o2 := o1; // Both variables "o1" and "o2" point to the same object on the heap.
WriteLogLine(Format('@o1 = %p, @o2 = %p', [@o1, %o2])); // This SHOULD produce two different address, as it's the address of the "implied pointer".
oP := o1; // THIS ASSIGNMENT will NOT compile.
WriteLogLine(Format('oP = %p', [oP]
o1.Free;
o1 := nil; // The single object has been deleted, but o1 = nil while o2 <> nil
end;
(To give some context, there are multiple variables that should be pointing to the same object but may be pointing to different objects, so I want to compare their memory location to determine if this is the case.)
A class, or class type, defines a structure consisting of fields, methods, and properties. Instances of a class type are called objects. The fields, methods, and properties of a class are called its components or members. A field is essentially a variable that is part of an object.
To define a class: In the IDE, start with a project open and choose File > New > Unit to create a new unit where you can define the new class. Add the uses clause and type section to the interface section. In the type section, write the class declaration.
If creating an object with o := MyObject.Create uses heap-allocation in Delphi, how do you allocate an object on the stack?
Delphi does not allow class instances to be allocated on the stack. They are always allocated on the heap.
If a variable of a specific type of class declared as o : MyObject is really a pointer, then why is the ^ pointer symbol never used. Is this a "convenience" idiom in Delphi?
Yes.
How can you get the address of the actual MyObject located on the heap?
Try this:
WriteLogLine('Address of object: ' + Format('%p', [Pointer(o)]));
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