Tianfang Night Tan VCL: Life and Death
What is life? Scientific and religion give different interpretations. There may be more interesting: life is such a thing, if you treat it as a opening or ending, then it is always the same; and when you treat it as a process, it is always different. In fact, all things are not for opening and ending for life and death? Objects are no exception, but the generated and destroyed objects require sound mechanisms to guarantee. Otherwise, not only the object itself is suffering, or even the program and even the entire system crash. The legendary, the oriental days, people, people, Ashuo, Bengji, Hell Six reincarnation (and the victory of Fengdu ghost city), and Western hell, purgatory, paradise, have a very complete, strict, and sound Mechanism, manage various living organisms in time and space. Similarly, a set of frames also require such a mechanism to manage objects in the memory to ensure proper operation. VCL is naturally no exception. But insects this time, it is not prepared to analyze the code involved in the VCL object to die, I believe that everyone has some experience in analyzing the underlying assembly. Therefore, the front insects will mention this aspect, focus on the structure and mode of the design, and solve a problem seen on BBS. Object generation
Object generation is almost all, general flows as shown on the right (initialization of the VCL class refers to initializing VMT and interface pointers). Objects are generally survived in two places, stacks or free stores [1]. Since Object Pascal only supports the second way, the VCL class is in the free storage area, and it is necessary to use new and delete allocation in the C . Recycling space, the speed will naturally be slower than the ordinary C class exists in the stack. . Controlling the code of the VCL object generation process is mainly in the Tobject :: InstanceSize, Tobject :: NewInstance, Tobject :: InitInstance several member functions. Interested friends can analyze the right image, source code in Source / VCL / System.Pas, there is nothing special. We will focus primarily on the Dynamic Creation mechanism. Dynamic generation is a quite practical technology. For example, the last time we mentioned the program [2], the specific graphics are provided in a plug-in, and the main program does not know about the corresponding graphics, but still needs "dynamically" to generate these objects. Another example, Delphi / C Builder IDE object designer, is also a good example: the mouse double-click, an object is generated in the design panel, which can be used for us. The C language itself is not impossible to provide support for dynamic generation, but the MACRO mode can be achieved in MFC [3]. Figure 1 Object generation process carefully, dynamically generated is a very funny technology, it requires a program to generate an object that is not clear about its nature. Can you make a thing you don't know? impossible. But if you tell you the raw materials and methods made? Of course, it is very simple. Therefore, the key to dynamic generation is to stay in advance agreement. The macromacromaus of the MFC is a way, Object Pascal uses another way. "Advanced" RTTI mode tends to introduce a so-called "class", ie "Metclass (Metclass)" concept [4]. In Object Pascal, each class has a class representing its corresponding information. The class represents Tobject class information is TCLASS. The class represents TPERSISTENT information is TPERSISTENTCLASS ...... Figure 2 Implementing the RTTI Metaclass Object Pascal to achieve the "Dynamic Creation" mechanism for Tcomponent derived classes. Function CreateComponent (Aowner: Tcomponent; Aclass: tComponentClass): Tcomponent
VAR
Tcomponent;
Begin
Instance: = Tcomponent (ACLASS.NEWINSTANCE);
{TRY}
Instance.create (OWNER);
{EXCEPT
Raise;
End;}
CreateComponent: = Instance;
END;
But in C Builder, it is invalid. For so-called "yuan classes", only TMetaClass classes are provided in the VCL of C Builder, and there are few functions, and even there is no way to provide newinstance, and the smart woman is mixed. How is Borland like this? What should I do? On the major BBS in China, I asked, and I also saw that someone else asked such a problem, I have no answer. There is a lot of problems in foreign BBS, and a common solution (Yes, use Object Pascal write unit, let C calls, this is not exempted ... What is the difficulty of dynamic generation? We already know, Pointing to the pointer of the VMT entry. If we give us a TMetaclass, can we do dynamically generated? Flowchart generated by the object Initialization: If there is no special need, call TOBJECT :: newinstance directly. Brother, not a joke? Tobject :: newinstance is private! Oh, think of a way around, through the VMT table "open" not OK?) Call?) Constructor: Pour! What should I do? Tmetaclass can not record a class constructor, and then, a class constructor is not only one? The only problem is on the constructor: we need a form fixed "virtual" constructor, which is what we just said: stay in the agreed interface. The point of this trick is consistent with the MFC. Fictional creation function? Can C constructor can be virtual (Virtual)? Of course not. The VCL class starts from the Tcomponent class, the constructor is virtual (no wonder we just generate Tcomponent's derived class), how is the so-called fiction creation of Object Pascal? Scott Meyers In Virtualizing Constructionors and Non-Member Functions, the so-called fictional implementation is described in detail: an ordinary virtual function is contemplated in advance, and its function is constructed. That is, the so-called fiction function of Object Pascal (name is CREATE), but it is a normal virtual member function that prior conventional features. MFC is doing this, in fact, VCL is also almost. In the design mode, this is called Factory Method mode, just also named Virtual Constructionor mode [6]. So, this virtual function can be found in VMT! Is the problem solved? In several pointer addresses starting in the Tcomponent class VMT entrance to find Tcomponent :: Tcomponent (Tcomponent.create in Object Pascal), I believe it is very easy? #include
#include
Using namespace std;
void main ()
{
Void ** p = (void **) __ classid (tcomponent);
For (int i = 0; i <15; i) cout << * (p ) << '/ t';
}
These liners can output the top 15 function addresses in the VMT of Tcomponent. The result is the result of the output on my machine (maybe there is different): 40026BD4 40030A54 40026AF0 40030B2C 400309F8
40030B38 40030C30 40030F88 40030B48 40030B40
40030F90 400306CC 0000000E 00010000 45840000
Recurrence Tcomponent :: Tcomponent's address. IDE Menu View-> Debug Windows-> Modules, select VCL50.BPL, find Tcomponent :: Tcomponent (as shown below). See it? Its address is exactly the same as the 12th address output above, this is our goal! (In fact, we have more lazy ways: Take a look at the assembly code of the Object Pascal program in front! Calculated from the VMT entrance, the 12th pointer is a pointer to construct a function. The VCL class is "virtual" constructed, and all Tcomponent's derived constructor's constructor will be placed there. So, from the first pointer of VMT to 11, it is the 12th pointer we need. Tcomponent * CreateComponent (TCOMPONENT * AOWNER, TCLASS CLS)
{
Tcomponent * r;
Const void * const fn = * (void **) ((char *) CLS VMTNEWINSTANCE,
* Const fc = * ((void **) CLS 11);
// fn is the address of NewInstance,
// fc is the address of the constructor, from 11 inwards, the 12th
// In order to lazy, use a few compilation
ASM {
MOV Eax, CLS
Call fn // Call NewInstance, 3 steps 3 before the flow of Figure 1
Mov R, EAX
Mov Edx, Aowner
Call fc // call constructor
}
Return R;
}
We may wish to test it. #pragma inline
#include
#include
Using namespace std;
Class TTestButton: Public TButton
{
PUBLIC:
__fastcall TTestButton (Tcomponent * Owner): TButton (Owner)
{
COUT << "Hello!" << endl;
}
__fastcall ~ ttestbutton ()
{
Cout << "Goodbye!" << Endl;
}
}
Tcomponent * CreateComponent (TCOMPONENT * AOWNER, TCLASS CLS)
{
// ...
}
void main ()
{
Tcomponent * P = CreateComponent (0, __classid (ttestbutton);
COUT << ANSISTRING (P-> ClassName ()). c_str () << Endl; delete P;
}
Output: Hello!
TTestButton
Goodbye!
The result is satisfactory! The main mechanism is simply mentioned in the Organizational Form of the VCL class: the owner mechanism. Starting with Tcomponent, the constructor of the VCL class has a Tcomponent * type (the parameter Aowner "represents Tcomponent in Object Pascal). Each entity that is inherited from Tcomponent has a unique owner (Owner, which is the owner), which determines that these classes are tree relationships. For example TFORM * FORM1 = New TFORM (Application);
TFORM * form2 = new tform (application);
TButton * Button1 = New TButton (TFORM1);