About object memory allocation and recycling
I don’t know if anyone has any ideas about placing the dl register here. If not, just think about it. If you think about it, you will be fine. In fact, before the following code (1), there is such a line of code MOV dl, 1, so why is it like this? The reason is not very simple, code reuse. Regarding the use of the dl register here, there is an introduction in Delphi's help. Be patient and look for it yourself. If you find it, you will be a master. This is learning, no, learning to fish, not asking for fish. Borland said this, "I use the dl register to store a flag. If the value is 1, then I will create the object. Otherwise, I will not create the object." If you are a little hazy, think about it again and again. If you haven't opened your eyes yet, then take a look at the following code (2), don't say you didn't find it, cough, what's going on, I keep talking nonsense, I promise not to say it again.
{Code (1)
test dl, dl
jz +$08
add esp, -$10
call @ClassCreate }
{///Code (2)
PRocedure Tapplication.CreateForm(InstanceClass: TComponentClass; var Reference);
var
Instance: TComponent;
begin
//////// Instance := TComponent(InstanceClass.NewInstance);
TComponent(Reference) := Instance;
try
//////// Instance.Create(Self);
except
TComponent(Reference) := nil;
raise;
end;
if (FMainForm = nil) and (Instance is TForm) then
begin
TForm(Instance).HandleNeeded;
FMainForm := TForm(Instance);
end;
end;
}
In this case, that is to say, Delphi calls code (1) when the instance of the created class is called for the first time. Then, if anyone needs to call the Create method, I, no, it is the compiler, just like this MOV dl, 0, so that the judgment 0 jump instruction in code (1) will go to the place where it should go. (Why are you talking nonsense again? The last time, I promise.) In fact, the Create method here is just an ordinary method, and , you should also notice that the first call to the Create method or NewInstance method is the class sending this message (note that this message is not Windows message, this message is not the other message, haha, it’s nonsense again, it’s really the last time, it’s true. If you don’t understand the message here, please learn the knowledge of object-oriented and modeling carefully) and call it later. The Create method is an established object, Instance.Create(Self); think about it, of course the value of the dl register has changed.
Okay, I don’t have much time. Finally, I would like to add that regarding the flag (Taiwan’s translation method, I think this word is good, I suggest you also use it to save me a lot of trouble later) and the instructions for the use of this dl register, it should be said There won't be any changes. If you think about it carefully, Delphi has not changed from 1 to 6. By the way, it also proves that Delphi's HB designer is a character. Of course, I can't compare. Haha, here we go again, okay, I’ll stop talking. Oh, finally, let me say that the TObject.Create method is by no means an empty method, remember, and then think about it.
Okay, other things, please go and see them in person. In that case, you will gain a lot.
"Get out of here, I want to see and think about it, and I don't want your nonsense!" Someone was laughing! :)
bye
When the compiler allocates memory for an object, the support it provides is to insert these lines of assembly code before calling the constructor:
test dl, dl
jz +$08
add esp, -$10
call @ClassCreate // Pay attention to this line of code
The last line of the above code calls the _ClassCreate function on line 8949 of the system.pas file (subject to Delphi 6). This function specifically allocates appropriate memory for each object. After the memory allocation is completed, the constructor of the class is called to initialize the data members. Afterwards, the compiler will insert the following lines of assembly code:
test dl, dl
jz +$0f
call @AfterConstruction
pop dWord ptr fs:[$00000000]
add esp, $0c
The main job is to call AfterConstruction of each object instance. This call is of no use in Delphi. Its existence is reserved for C++Builder.
Similarly, when destructing an object, the destructor of the class must first be called to release the resources requested by the object. After that, the memory space occupied by the object itself is recycled. This work is completed by the compiler inserting the following assembly code after calling the destructor:
call @BeforeDestruction
test dl, dl
jle +$05
call @ClassDestroy
The work done by these codes corresponds to what is done when constructing the object and allocating memory, mainly calling the _ClassDestroy function on line 8997 in system.pas.
Constructor and destructor
To define a constructor, use the Constructor keyword. By convention, the name of the constructor is Create (of course other names can be used, but that is by no means a good design!). like:
type
TMyFamily = class // The class defined for your family
Private
FMyFatherName : String; // your father's name
FMyMotherName : String; // your mother's name
… // Other members of your family
Public
Constructor Create(strFatherName, strMotherName : String);
…… // Other methods
End;
You may ask, if I do not provide a constructor for my class, can its objects be created? The answer is: yes. The reason has been mentioned before, the allocation of the memory occupied by the object itself is completed by the compiler. And since in Object Pascal, all classes (except the TObject class itself) are derived from the TObject class, the compiler will call the TObject.Create() constructor, but this function is an empty function, and it will not affect the TMyFamily class. When the data members (FMyFatherName, FMyMotherName) are initialized, they will be automatically cleared to empty strings (i.e. ''), because TObject.Create() does not know your father or mother at all!
When creating an object, the constructor is called directly, in the following form:
MyFamilyObject := TMyFamily.Create('Zhang', 'Li');
Use the Destructor keyword to define a destructor. By convention, the destructor is named Destroy. like:
type
TMyClass = class
Public
Destructor Destroy(); override;
End;
The reason why the override statement is added at the end of the destructor declaration is to ensure that the object can be destructed correctly in the case of polymorphism (polymorphism will be discussed in detail in Section 2.4). If you do not add the override keyword, the compiler will give a warning similar to "Method 'Destroy' hides virtual method of base type 'TObject'". The warning means that the Destroy you defined hides the virtual method TObject.Destroy() of the base class. In that case, the object cannot be destructed correctly in polymorphic situations.
Note: Destructors need to be declared with an override statement.
Likewise, if there are no special resources that need to be released in your class, you don't need to define a destructor. However, when destructing an object, you should call the object's Free() method instead of calling Destroy() directly.
MyFamilyObject.Free();
This is because the Free() method will determine whether the object itself is nil, and if it is not nil, the object's Destroy() will be called to increase safety. Now that there are safer ways to do this, there's certainly no reason not to do it.
Note: Never call Destroy() directly on an object, but Free() instead.
It can be concluded from this that in Object Pascal you only need to pay attention to the allocation and release of the resources applied for by the object, and do not have to care about the space occupied by the object itself!