Analysis of the construction and sectors in Delphi 1 Delphi Object Model: 21.1 What is the name of the object? 21.2 Where is the object stored? 21.3 What is stored in the object? How do they store? 32 Construction Functions and Create Objects 52.1 What is constructor? ("Special" Class Method) 52.2 Creation of Objects 52.3 Construction Functions Another Treatment (Polymorphism Using Class reference to implement constructor) 63 Destructor and Destruction Object 73.1 What is a destructor ("natural" Method 73.2 Object Destruction All Process 73.3 Destroy, Free, FreeAndnil, Release Usage and Difference 74 VCL Construction & Analysis Architecture 85 Correct Using Constructor and Design Functions 9 Analyze the Construction and Desumble of Delphi: This article Through the study of VCL / RTL, the implementation mechanism of constructors and destructors and the architecture of the objects in the VCL are analyzed, and how to create and release objects correctly. Keywords: constructive, destructure, creating objects, destroyed objects, piles, stacks, polymorphisms. Servers: MAJORSOFT Questions What is the implementation mechanism of constructive functions and destructive functions in Delphi? Is it different from C ? How to create and release objects correctly? Solution How to use constructors and sectors in the process of use is our problem that we often encounter in the Delphi process. There are many relevant posts in the Oriented Pascal column in the Daeng Forum (see related questions), I have encountered similar Problem, under the study of VCL / RTL source code, understand the implementation mechanism of constructive function and sectoral function. 1 Delphi Object Model: 1.1 What is the name of the object? Unlike C , the object name (or corresponding variables) in Delphi represents the reference to the object, does not represent the object itself, which is equivalent to the pointer to the object, which is called "object reference model". As shown in the figure: Obj (object name) actual object VMT entrance address
Data member
Figure 1 Object Name Reference Memory Object 1.2 Object Store? Each application divides the memory that is assigned to it into four areas: Code Area Global Data Area (STACK AREA)
Figure 2 Program memory space code area: Program code in the storage program, including all function code global data area: Store global data. Stacking area: It is also called "free storage area" and stores dynamic data (including objects and strings in Delphi). The scope is the entire life cycle of the entire application until the destructor is called. Stack area: Also called local data in the "Automatic Storage Area" storage program, in C , the local variable is actually the variable of the AUTO type. The scope is the inside of the function, and the function is immediately recovered immediately after the system is called. In C , the object can be created on a heap or in a stack, and you can create an object in the global data, so C has a global object, local object, static object, and a heap object. Objects. In Delphi, all objects are built on a heap store, so the Delphi constructor cannot be automatically called, but must be called by the programmer (in the designer drag component, this time the object is created by Delphi) . The following programs illustrate the difference between Delphi and C : in Delphi: Procedure CreateObject (var fooobjref: tfooObject); beginfooobjref: = tfooObject.create; // is called by programmer, the process is still existing. Not need to copy FooObject.caption = 'I am created in stack of CreateObject ()'; End; and in C : TfooObject CreateObject (void); {TfooObject FooObject; // create a local object // static TfooObject FooObject; // Create Static local object // Object automatically calls the default constructor for creation, the object is created in the function stack in the function stack = 'i am created in stack of createObject ()'; returnifject; // When returned Copy, the originally created objects are completed with the function of the function, automatically destroy} TfooObject FooObject2; // Create a global object. Void main (); {tfooObject * pfooobject = new tfooObject; // creates a stack object. After the function is finished, the object still exists and does not need to be copied. } What is stored in the 1.3 object? How do they store? Unlike C , the objects in Delphi only store the entry address of the data member and the virtual method table (VMT), without a storage method, as shown: Password virtual method table code segment VMT Address NAME: STRINGWIDTH: INTEGER; CH1: CHAR; ... ProC1 Func1 ... Procn Funcn ... Figure 3 Structure of the object ... Maybe you have some questions about the above saying, please see the following procedure: TsizealignTest = Class Private i: integer; ch1 CH2: CHAR; J: Integer; public procedure showmsg; proca;
Memo1.Lines.Add (IntegerSize '); Memo1.Lines.Add (Integer) ' <<- start addr '); Memo1.Lines.Add (INTOSTR (@ (sizetest.i))) '<- siztest.i'); Memo1.Lines.Add (Integer (Integer (@ (@ (@ (@ (@ (@ (@ (sizetest.ch1 '); Memo1.Lines .Add (INTTOSTR (Integer (@ (Sirtest.ch2))) '<- siztest.ch2'; memo1.lines.add (Integer (Integer (@ (@ (@ (@ (@ (sizetest.j))) '<- siztest.j '); Results show: 16: instancesize14630724 <-start addr14630728 <-start addr14630728 <-siztest.i14630732 <-sizetest.ch114630733 <-sizetest.ch214630736 <-siztest.j data member and VMT entrance address accounting for 16 bytes!, Two Member functions showMSG, Virtmtd is not spaced in the storage area of the object. So where is the member function stored? Since Delphi is based on RTL (Runtime Type Library), all member functions are stored in the class, and the member function is actually the method pointer, which points to the entry address of the member function, and all objects of the class share these member functions. So how do you find the entrance address of the member function? For static functions, this work is done by the compiler. During the compilation process, according to the type object reference / pointer, that is, find the entry address of the member function directly in the class (there is no need to exist in this point), this That is, the so-called static binding; for the virtual method (including a dynamic method), it is the virtual method table VMT entry address (ie the first four bytes of the object, "at this time, at this time, at this time, the object must exist at this time. Otherwise, it will cause pointer access error) to find the entrance address of the member function, which is the so-called dynamic binding. Note The above mentioned that all member functions are stored in the class, and in fact, the virtual method table VMT is also included. From Delphi's code automatic completion function (it relies on compilation information), when we enter the object name, then enter ".", Then Delphi recommends it, list all data members and all Static method, all false methods, all types of methods, all constructor and destructive functions, you can try to see if it is. Class Unit Form VMT Entry Address Data Member Template Information Static Method Table Music Form VMT Object VMT Entry Address Data Members The above program also demonstrates alignment of object data members (physical data structure), aligned with 4 bytes (Windows The default alignment), as shown below: VMT Entrance Addr i ch1 CH2 J
2 Constructor and Create Object 2.1 What is a constructor? ("Special" method) From the semantic language of OO (object-oriented) ideas, constructor is responsible for the creation of objects, but on the implementation of OOP language, regardless of Delphi or C , constructor is in an amount of object initialization Work (including the constructor of calling the internal sub-object), is not responsible for creating the entire process of the object (refer to 2.2). In addition, in different from C , Delphi defines another method type for the constructor (MKConstructor, see the /source/rtl/common/typinfo.pas ,125 lines under the Delphi installation directory), we can understand it as "Special" method. It can only be called by class (class name / class reference / class pointer), and the general class method can be called both through the class or through the object; there is a point of specialization of the built-in SELF parameters in the constructor to point to the object And in the class method, Self is directed to the class, and we usually initialize its data members, making it a true object, which is benefited from the parameter of Selff. By default, the constructor is a static function, we can set it to the virtual method, in derived class override, this can achieve polymorphism of the constructor (see 2.4), or It performs overload, creates multiple constructors, and can also directly override the constructor of the "Overlay" parent class, which uses these technologies in the VCL in the VCL in the derived class. To form a constructor "architecture" (see 4) 2.2 The creation of the whole process of the creation of objects should include allocation space, constructing physical data structure, initialization, internal sub-object creation. As mentioned above, the constructor is only responsible for initialization work and the constructor of calling the internal sub-object, then how is the allocation space and constructive physical structure to complete? This is because the compiler is doing extra things, we don't know.
When compiling to the constructor, the function is constructed, which is inserted into the "call @classcreate" assembly code. It is actually the _classcreate function in the System cell, and see the part of the _classcreate function: function _classcreate (aclass: Tclass; alloc: boolean: Tobject; asm {-> eax = pointer to vmt} {<- eax = pointer to instance} ... call dword ptr [eax] .vmtnewinstance // call newinstance ... End; {/ source / r r / Sys / system.pas, 8939 row} Vmtnewinstance = -12; it is the offset in the class in the class, "Call DWORD PTR [EAX] .Vmtnewinstance" is actually calling newInstance, see Tobject.newInstance: Source: class function NewInstance: TObject; virtual; class function TObject.NewInstance: TObject; begin Result: = InitInstance (_GetMem (instanceSize)); end; "InitInstance (_GetMem (instanceSize))" in turn calls the three functions: 1) First call instancesize (), return to the actual class of object size Class function TOBJECT.INSTANCESIZE: long; // is equivalent to a virtual method Begin Result: = Pinteger (Integer VMTINSTANCESIZE) ^; // Return the actual object size END; 2) Call _getMem () Distributing instance size on the pile, and returning to the object's reference 3) Call the initInstance () to construct the physical data structure, set the member to set the default value, such as the intellectual data member The value is set to 0, and the pointer is set to NIL. If there is a virtual method, the entry address of the virtual method table VMT assigns the first four bytes of the object. After calling newinstance, this time the object, only "empty shell", and there is no actual "content", so you need to call the customized constructor to make sense to initialize the object, and call the internal sub-object constructor. Make the objects in the program real reflect the object of the real world. This is the whole process of object creation. 2.3 Structured Functions Another Usage (Polymorphism using class references) In Delphi, the class is also stored as an object, so there is a polymorphism, which is implemented by the class reference and the virtual class method, so Provides a class-level polymorphism. Set the class method to the false method, which is overridden in its derived class, and then call it through the reference / pointer of the base class, which is to construct the object according to the class reference / pointer to the actual class. Please see the procedure below: TMYCLASS = Class Constructor Create; Virtual; end; ttmyclass = class of tmyclass; // Base class class reference TMYCLASSSUB = Class (TMYCLASS) Constructor Create; over;
Procedure CreateObj (ACLASS: TTMYCLASS; VAR REF); Begin Tobject (REF): = aclass.create; // REF is no type, and is not compatible with any type, so it must be explicitly enforced (CAST) // ACLASS For class references, unified function interfaces, different implementations. // It constructs an object according to the actual class pointed to the ACLASS. End; ... CreateObj (TMYCLASS, OBJ); CreateObj (TMYCLASSUB, SUBOBJ); 3 Destructor and Destruction Object 3.1 What is a destructive function ("natural" virtual method) from the semantic language of OOP thinking, the destructive function is responsible Destroy the object and release resources. In Delphi, synonym. Delphi also defines a method type for the destructor (MKConstructor, see the /source/rtl/common/typinfo.pas, 125 lines in the Delphi installation directory), in the VCL, it is actually a "natural" virtual Methods, "Destructor Destroy; Virtual;" is defined in all Ancestral -TObject of the VCL class. Why is VCL to do this? Because it is necessary to ensure that the object can be properly destructed in the polymorphism. If the virtual method is not used, it may only be designed with the base class sub-object, resulting in so-called "memory leak". Therefore, in order to ensure the correct destructure object, the destructor needs to be added to the Override statement. 3.2 The whole process of the target destroy first destroys the derived class object and then destroy the base class object. Turning in the derived class, the base class sub-object refers to the part inherited from the base class, and the derived class neutral object refers to a new part. 3.3 DESTROY, Free, FreeAndnil, Release Usage and Difference Destroy: Default Method Releases Memory, Declaring as Virtual in TOBJECT, usually in its subclass Override it, and add inherited keywords to ensure that derived class objects are correct Destroyed; but Destroy can generally not use it directly, why? If an object is NIL, we still call DESTROY, which will generate errors. Because DESTROY is a virtual method, it is necessary to find the entry address of the virtual method table VMT based on the four bytes in the object, so that the object of the deStroy is found, so the object must exist. But Free is a static method, which only needs to be determined according to the type of object reference / pointer, even if the object itself does not exist, there is no problem in Free, and it is said to have an operation existing in Free, so it is safe to use DESTROY. 2) Free: Static method test object is NIL, non-NIL calls DESTROY. Here's Delphi code: Procedure Tobject.free; Begin if Self <> nil the destroy; end; a quiet movement, do not make a good strength, not wonderful! However, calling Destroy just destroyed the object, but did not set the reference to NIL, which requires a programmer to complete, but since Delphi5, a FreeAndnil is provided in the sysutils unit. 3) freeandnil; general method, non-object method, non-class method. Freeandnil defines procedure freeandnil (var temp: = tobject; pointer (obj): = nil; temp.free; end; recommended that you use it instead of Free / Destroy Make sure the object is released correctly. 4) Release; the static method defined in TCUSTOMForm.
The free function is called after all events in the window are handled. Commonly used in destroying windows, and when event processing in this window requires a certain time, use this method to ensure that the window event is destroyed after processing. Here is the Delphi source code for TCUSTOMMM.RELEASE: Procedure TCUSTOMMM.RELEASE; Begin Postmessage (Handle, CM_RELEASE, 0, 0); / / Send a CM_RELEASE message to the message queue to the window, and after all the window event messages are completed, // // CM_RELEASE recall message processing CMRelease end; look CM_RELEASE message defined in the following process CMRelease: procedure CMRelease (var message: TMessage); message CM_RELEASE; procedure TCustomForm.CMRelease; beginFree; // finally free; end; 4 VCL Constructs & Contetructor Create; // Static Method Destructor Destroy; Virtual; TPERSISTENT DESTRUCTOR DESTROY; OVERRIDE
Tcomponent Constructor Create (Aowner: Tcomponent); Virtual; Destructor Destroy; Override;
Tcontrol Constructor Create (Aowner: Tcomponent); OVERRIDE; DESTRUCTOR DESTROY; OVERRIDE
... Next, the source code in the VCL is analyzed, tControl as an example: constructor tControl.create (Aowner: tComponent); begin inherited create (aowner); // Create a base class sub-object, and hand over the territory Give Aowner. Put in the forefront to ensure the order ... // initialization of "first class sub-objects, then create a genetic class sub-object", and call the constructor of the internal sub-object;