Talk about polymorphism - up maps and VMT / DMT Author: Nicrosoft (nicrosoft@sunistudio.com) 2001.10.9 personal home page: http: //www.sunistudio.com/nicrosoft/ East Documents: http: // www. SUNISTUDIO.com/asp/sunidoc.asp
In the article "Talking about Polymorphisms - Concept Description", the present invention is the "pointer to the parent type" pointer to the parent class type. So why this assignment is allowed, or is it safe? Don't you do it? How is the dynamic binding of the virtual function implementation? These issues will be answered in this article. It is assumed to have the following code (Object Pascal language description): T1 = Class Private Member1: Integer; public function func1: integer; virtual; function func2: integer; virtual; end;
T2 = Class (T1) Private Member2: Integer; Public Function Func1: Integer; Override; Function func2: integer; override;
The final result is that the memory distribution map of the Example of the T1 class is as follows (only the principle, does not represent the compiler must also be implemented): _____________________________________func1 | | | T1.FUNC2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A member pointer (called virtual pointer) automatically added. Only the class with virtual functions or dynamic functions or pure virtual functions will be added to this member pointer by the compiler, the pointer pointing to a memory called "virtual function table" (Object Pascal into the memory of "virtual method" --VMT) area. In the virtual function table, the entry address of each virtual function is saved. The memory profile of the example of the T2 class is as follows: ___________________________________ | vptr | -------> | T2.Func1 | | MEMBER1 | | T2.Func2 | | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From the figure we can know that the space occupied by the sub-objects is greater than the space of the parent class . Therefore, when the pointer to the subclass type is generated to the assignment of the pointer to the parent class type (ie, the so-called "upstream"), that is, the pointer of the parent class type points to the memory space occupied by the object of the subclass type, Then, it is obvious that the accessibility of the parent class pointer can be guaranteed, so this "upstream" is absolutely secure (so-called "up" refers to the upper and lower relationships of class level, the parent class is on, subclass Next). This assignment is approved by the compiler. It can also be easily concluded that "down map" is not necessarily secure (unless the programmer really knows the actual type of object referred to). Therefore, this assignment is not allowed by the compiler. Of course, programmers can make mandatory type conversion by similar T1 (OBJ), but this mandatory type conversion is unsafe (can occur between any classes and classes ), Object Pascal recommends using the conversion between the AS operator, such as: (OBJ AS T1), using an AS operator, the compiler checks if the object type and the target type are compatible. If compatible, the conversion is allowed, otherwise it is wrong.
Then, we look at how the dynamic binding of the virtual function is implemented. First look at the following code: Procedure test; var o: t1; begin o: = t2.create; o.func1; o.func3; o.free; end; looks at the above memory layout, when O: = T2 is performed. Create; a T1 type pointer points to the T2 entity. When executing O.func1, the compiler found the virtual function table via VPTR, locating T2.Func1 in the virtual function table (since t1.func1 is "overwritten", therefore can't find T1.func1 in the virtual function table), so T2.func1 is called, this is dynamic binding! However, since the T2 has not rewritten FUNC3, O.Func3 will call T1.Func3, which can also be apparent from the virtual function table. Ok, say this, I think that dynamic binding has been very clear, explain that although this article takes Object Pascal code as an example, the principle is equally effective for C . The difference between C and Object Pascal (or even different C compilers) is only where class members and VPTR are distributed in memory.
So, let's talk about Object Pascal's unique DMT (dynamic method table). In the VMT, we see that the virtual function table of the subclass completely inherits the virtual function table of the parent class, just changing the address of the overwritten virtual function. Each subclass has a virtual function table, you can imagine, with the extension of the class level, if the class level is very deep, or if the number of subclats is very large, the virtual function table will be called the amount of memory. The so-called "class explosion"). In order to prevent this, Object Pascal introduced DMT. For programmers, the difference is only to use the "Dynamic" keyword instead of the "Virtual" keyword, the functionality implemented is exactly the same.
If you rewrite the code out of this article (replace Virtual): T1 = Class Private Member1: Integer; PUBLIC FUNCTION FUNC1: Integer; Dynamic; Function func2: integer; dynamic; end;
T2 = class (T1) private member2: integer; public function func1: Integer; override; function func2: Integer; override; end; then, the memory map T1 is not changed, but not the same instance T2: ___________________ ________________ | DPTR | -------> | T2.Func1 | | MEMBER1 | | T2.FUNC2 | | MEMBER2 | ~~~~~~~~~~~~~~~ ~~~~~~~~~~~ It can be seen that in the dynamic method table of T2, there is no covered T1.func3 disappeared. So: procedure test; var o: t1; begin o: = t2.create; o.func3; o.free; end; o.func3 This sentence will be more processed by the compiler: Find the func3 function of the T1 class The entrance address and then call it. Compare the difference between VMT and DMT: The virtual function in the VMT is very complete, so the entry address of each virtual function only requires a simple [VPTR N] operation, but VMT is easy to consume memory (redundant) . The DMT is saved, but it will take time when it is positioned to the entrance address of the function that is not overwritten.
Under normal circumstances, almost every subclass is overwritten, declare it as virtual; if the class level is very deep, there are many subclats, but a function / method is only covered by little subclasses, State it as Dynamic. Of course, you need you to grasp your own choice.