In C + +, when a class contains a virtual function, the class has polymorphism. An important function of the constructor is to initialize the vptr pointer, which is a critical step to ensure polymorphism.
Constructor initializes the vptr pointer
The following is the C + + Source:
Class X {
private:
int i;
Public:
X (int ii) {
i = II
}
virtual void set (int II) {//virtual function
i = II;
}
};
int main () {
x x (1);
}
The following is the corresponding main function sink code:
_main PROC : int main () {
push ebp
mov EBP, esp
Sub ESP, 8; Reserve 8byte space for object X 4-byte member variable i occupies 4byte
; x x (1);
vptr pointer. Push 1;//pushes the 1 stack as a parameter to the constructor
Lea ECX, and the DWORD PTR _x$[ebp];//gets the first address of X, the this pointer, passed as an implied parameter to the constructor call ?? 0x@ @QAE @h@z ; Call constructor for x :
xor eax, eax
mov ESP, ebp
pop ebp
RET 0
_main ENDP
As you can see from the sink encoding, because class X has a virtual function, the main function reserves 8byte of space on the stack for object x to hold the vptr pointer and member variable i.
The following is an assembly code for the constructor of x:
?? 0x@ @QAE @h@z PROC ; X::x, comdat
_this$ = ecx
; 5 : X (int ii) {
push ebp
mov EBP, esp
push ECX The purpose of the pressure stack ecx is to reserve 4byte of space mov DWORD PTR _THIS$[EBP] for this pointer (the first address of X object) , ecx; Store the this pointer in the space just reserved ecx the first address of X
mov eax, DWORD ptr _THIS$[EBP]; the first address of X to register EAX
mov DWORD ptr [eax], OFFSET?? _7x@@6b@ A. The offset address of the _7x@@6b@ (that is, the vtable's first address) is placed in the store that the first address of the X object points to is the initialization vptr pointer
; 6 : i = II;
MOV ecx, DWORD ptr _THIS$[EBP]; send x address to ecx
mov edx, DWORD ptr _II$[EBP]; value of parameter II to register edx
mov DWORD ptr [ecx+4], edx; writes the value of the register EAX to the memory at the address 4byte at the beginning of X, which is assigned to the member variable I of x
; 7 :
mov eax, DWORD PTR _ THIS$[EBP]; eax the first address of the X object to the register as the return value. The constructor always returns the first address of the object mov esp, ebp
pop ebp
ret 4
?? 0x@ @QAE @h@z ENDP
As you can see from the code, the compiler did secretly insert the code to initialize the vptr pointer with Vtable's first address, and the vptr pointer is at the object's first address.
If the class has an inheritance relationship, how does the constructor initialize the vptr pointer?
The following is the C + + Source:
Class X {
private:
int i;
Public:
virtual void F () {}
};
Class Y:public X {//y inherits from X
private:
int J;
};
int main () {
y y;
}
The following is the assembly code in the main function:
_main PROC : int main () {
push ebp
mov EBP, esp
Sub ESP, ; Reserve byte space for object Y vptr Pointer 4byte parent class member variable 4byte subclass member variable 4byte
; y y;
Lea ecx, DWORD PTR _Y$[EBP]; Gets the first address of the object Y (that is, the this pointer), passed to the constructor call as a suppressed parameter ?? 0y@ @QAE @xz; The constructor that calls y although Y does not show the definition constructor, but because it contains a virtual member function, the compiler provides a default constructor
; () :
xor eax, eax
mov ESP, EBP
pop ebp
ret 0
_main ENDP
The following is a subclass constructor sink encoding:
?? 0y@ @QAE @xz PROC ; Y::y, comdat
_this$ = ecx
push ebp
mov EBP, esp
push ecx;//pressure stack ecx to store this pointer
mov DWORD ptr _this$[ebp], ecx; Put the this pointer (that is, the object's first address) into just reserved space ecx inside the object first address
mov ecx, DWORD ptr _THIS$[EBP]; Pass the first address of the object to ECX as a suppressed parameter to the parent class constructor call ?? 0x@ @QAE @xz; Call parent constructor
mov eax, DWORD ptr _THIS$[EBP]; the first address of Y to register eax
mov DWORD PTR [eax], OFFSET?? _7y@@6b@ the vtable of y (??) _7y@@6b@) The first address is assigned to the first address of the Y object, the memory is the initialization subclass vptr Pointer
mov eax, the DWORD PTR _THIS$[EBP], and the Y first address to EAX as the return value. The constructor always returns the first address of the object mov esp, ebp
pop ebp
ret 0
?? 0y@ @QAE @xz ENDP
The following is the parent class constructor sink encoding:
?? 0x@ @QAE @xz PROC ; X::x, comdat
_this$ = ecx
push ebp
mov EBP, esp
push ecx; The purpose of the stack is to hold the this pointer (the parent object's first address) Reserved space
mov DWORD ptr _this$[ebp], ecx; Put the parent object object first address (saved in ecx) into just reserved space
mov eax, DWORD ptr _THIS$[EBP]; The parent object first address to register EAX
mov DWORD PTR [eax], OFFSET?? _7x@@6b@ will vtable (??) _7x@@6b@ and subclasses are different) the first address is assigned to the memory at the parent object's first address, the vptr pointer to the parent object , and the eax, DWORD PTR _THIS$[EBP, and the parent object's first address is passed to EAX as the return value. The constructor always returns the first address of the object mov esp, ebp
pop ebp
ret 0
?? 0x@ @QAE @xz ENDP
From the constructor of the upper subclass and the parent class, it can be seen that the child object contains the parent object, which constructs the parent object (the child object constructor calls the parent object constructor first) when constructing the child object. The parent object's first address is the same as the child object's first address (as can be seen by the value passed in the ECX), so the vptr pointer of the parent and child objects is at the same place. Therefore, in the construction of the object, the Vptr pointer is initialized first to the vtable first address of the parent object (in the parent object constructor) and finally to the vtable first address (in the child object's constructor) that points to the child object. Therefore, when inheritance is involved, the value of the vptr pointer is determined by the last constructor called.
Failure to invoke a virtual function mechanism in a constructor, that is, calling a virtual function in a constructor is always a local version (same as in a destructor)
C + + source code is as follows:
Class X {
private:
int i;
Public:
virtual void f (int ii) {
i = II
}
X () {
f (1);
}
};
Class Y:public X {//y inherits from X
private:
int J;
Public:
virtual void f (int ii) {
j = II
}
Y () {
F (2);
}
};
int main () {
y y;
}
Here's a look at the assembler code for the constructor in the parent class X and Subclass Y:
Constructor for subclass Y:
?? 0y@ @QAE @xz PROC ; Y::y, comdat
_this$ = ecx : Y () {
push ebp
mov EBP, esp
push ecx; The purpose of the stack is to store the this pointer (the first address of the child object is stored inside the ECX register) to reserve the space
mov DWORD PTR _this$[ebp], ecx; to deposit the first address of the child object into the space just reserved ECX, DWORD PTR _THIS$[EBP]; Pass the first address of the subclass as an implied parameter to the parent object constructor (same as the child object's first address and the parent object's first address) call ?? 0x@ @QAE @xz ; Call parent constructor
mov eax, DWORD ptr _THIS$[EBP]; pass the first address of the child object to the register EAX
mov DWORD PTR [EAX], OFFSET?? _7y@@6b@ the vtable first address of the child object to the memory pointed at the first address of the child object, that is, the vptr pointer of the initialization child object
; F (2);
Push 2, 2 pressure stack, as a parameter call function f, here, the child objects are called their own function f
mov ecx, DWORD PTR _THIS$[EBP]; Pass the child object's first address to the ECX as an implied parameter to the member function f call f@y@ @UAEXH @z ; calls f functions in child objects
; }
mov eax, DWORD PTR _THIS$[EBP]; EAX the first address of the child object to the register as the return value. The constructor always returns the first address of the object mov esp, ebp
pop ebp
ret 0
?? 0y@ @QAE @xz ENDP ; Y::y
Assembly code for the parent class X constructor:
?? 0x@ @QAE @xz PROC ; X::x, comdat
_this$ = ecx
; 8 : X () {
push ebp
mov EBP, esp
push ecx; The purpose of the stack is to store the parent object first address reservation space parent object first address and child object first address like
mov DWORD PTR _THIS$[EBP], ECX;ECX inside the parent object to store the first address, passed to just reserved space
mov EAX, DWORD ptr _THIS$[EBP]; Pass parent object first address to EAX
mov DWORD ptr [eax], OFFSET?? _7x@@6b@ the Parent object's vtable first address to the memory pointed to by the parent object's first address and initializes the parent object's vptr pointer
; 9 : f (1);
Push 1, 1 pressure stack, as parameter call function f This is called when the parent object version
mov ecx, DWORD PTR _THIS$[EBP]; Pass the parent object's first address as an implied parameter to F call ? f@x@ @UAEXH @z ; Call function f : }
mov eax, DWORD PTR _THIS$[EBP]; Pass the parent object's first address to EAX as the return value. The constructor always returns the first address of the object mov esp, ebp
pop ebp
ret 0
?? 0x@ @QAE @xz ENDP
As you can see from the sink encoding, virtual mechanisms do not exist in the constructor, and only local versions of the functions are called
destructor
When the destructor executes, it first initializes the Vptr pointer to the virtual table vtable first address of the current class, but if the compiler supplies a default destructor when the destructor is not available, then the initialization of the vptr pointer is not performed:
C + + Source:
Class X {
private:
int i;
Public:
virtual void set (int ii) {
i = II
}
~x () {}
};
Class Y:public X {
private:
int i;
};
int main () {
y y;
}
Class Y destructor sink code:
?? 1y@ @QAE @xz PROC ; Y::~y, comdat
; _this$ = ecx
push ebp
mov EBP, esp
push ECX; reserve space for the first address of the incoming Y object
mov DWORD ptr _THIS$[EBP], ecx;ecx to save the first address of the Y object, in the space just
mov ecx, DWORD ptr _this$[ebp]; The Y object's first address (the Y object contains the parent object, their first address) To ECX, a destructor that passes the address class X as an implied parameter call ?? 1x@ @QAE @xz ; The destructor of the call class X
mov ESP, ebp
pop ebp
ret 0
?? 1y@ @QAE @xz ENDP
As you can see from the remit encoding, the compiler provides a non useless default destructor for the Y object to invoke the destructor of the parent class, but inside the destructor of the Y object, there is no action to initialize the Y-object vptr pointer to the virtual table vtable of Class Y.
The following is the destructor sink encoding for class X:
?? 1x@ @QAE @xz PROC ; X::~x, comdat
_this$ = ecx
; 9 : ~x () {}
push ebp
mov EBP, esp
push ecx; Reserve space for the first address of the incoming parent object
mov DWORD ptr _this$[ebp], ecx for the parent object to be passed in the first address to just space
mov eax, DWORD ptr _this$[ EBP]; Parent object first address to EAX
mov DWORD PTR [eax], OFFSET?? _7x@@6b@ vtable first address to the parent object at the first address of the memory that initializes the parent object vptr Pointer
mov ESP, ebp
pop ebp
ret 0
?? 1x@ @QAE @xz ENDP
The destructor of the parent class has an initialization vptr operation, at which point the virtual table that the vptr points to is already the virtual table corresponding to class X, not the virtual table corresponding to the subclass Y.
Abstract base class
C + + source code is as follows:
Class X {
private:
int i;
Public:
virtual void f () = 0;//pure virtual function
X () {
i = 1;
}
};
Class Y:public X {//y inherits from X
private:
int J;
Public:
virtual void F () {
j = 2;
}
};
int main () {
y y;
}
The assembler code that looks only at the constructor of the parent class X and the constructor of the subclass Y:
Assembler code of the subclass Y constructor:
?? 0y@ @QAE @xz PROC ; Y::y, comdat
_this$ = ecx
push ebp
mov EBP, esp
push ECX; reserve space for the first address of a saved child object
mov DWORD ptr _THIS$[EBP], ecx the value of ECX (which holds the first address of the child object) into the space
mov ecx, DWORD ptr _THIS$[EBP]; pass the first address of the child object to ECX as an implied parameter ( This pointer) calls the parent object's constructor
call ?? 0x@ @QAE @xz Call the constructor of the parent object
mov eax, DWORD ptr _this$[ebp]; give the first address of the child object to eax t
mov DWORD ptr [eax], OFFSET?? _7y@@6b@ the vtable first address of the child object to the memory pointed at the first address of the child object, the Vptr mov eax of the initialization child object , the DWORD PTR _THIS$[EBP], and the first address of the child object to EAX as the return value. The constructor always returns the first address of the object mov esp, ebp
pop ebp
ret 0
?? 0y@ @QAE @xz ENDP
Parent class X Constructor sink encoding:
?? 0x@ @QAE @xz PROC ; X::x, comdat
_this$ = ecx
; 6 : X () {
push ebp
mov EBP, esp
push ecx; The purpose of the stack is to store the parent object's first address (that is, this pointer) to reserve the space
mov DWORD ptr _this$[ebp], ecx; Save the first address of the parent object to just the space
mov eax, DWORD ptr _ THIS$[EBP]; Pass the parent object's first address to EAX
mov DWORD PTR [eax], OFFSET?? _7x@@6b@ the Parent object's vtable (because the parent class is an abstract class, its vtable is not complete, that is, there is no address to hold the pure virtual function, and only one location is reserved) The first address is saved to the memory that is referred to in the parent object's first address
; 7 : i = 1;
mov ecx, DWORD ptr _this$[ebp]; give the parent object's first address to ECX
mov DWORD ptr [ecx+4], 1; Save 1 to the parent object's first address 4byte, that is, assign the member variable i
; 8 :
mov eax, DWORD PTR _THIS$[EBP]; The parent object's first address gives EAX as the return value. The constructor always returns the first address of the object mov esp, ebp
pop ebp
ret 0
?? 0x@ @QAE @xz ENDP
As you can see from the remit encoding, the constructor of the parent class is still called in the process of constructing the subclass, although the parent class is an abstract class. But this is only to initialize the part of the child object that contains the parent object, and if you directly want to instantiate an object from the parent class, the compiler complains, because the vtable of the parent class is incomplete and the compiler cannot safely create an abstract class object. While in the construction of the child object, although the part of the parent object contained in the construction child object, vptr temporarily points to the vtable of the parent class, but when the construction of the child object is completed, Vptr eventually points to the vtable of the subclass. The vtable of subclasses is a complete, so the compiler allows.
The late bundle mechanism of polymorphism is only valid when calling virtual function with address or reference, if the virtual function is called directly with the object itself, then the late bundle will not appear, but it is called directly.
C + + Source:
Class X {
private:
int i;
Public:
virtual void F () {
i = 1;
}
};
Class Y:public X {//y inherits from X
private:
int J;
Public:
virtual void F () {
j = 2;
}
};
int main () {
Y y;//stack creates object on
y* YP = Create object on new y;//heap y.f ();//
call
yp->f () directly with object
;
Class X {
private:
int i;
Public:
virtual void F () {
i = 1;
}
};
Class Y:public X {//y inherits from X
private:
int J;
Public:
virtual void F () {
j = 2;
}
};
int main () {
Y y;//stack creates object on
y* YP = Create object on new y;//heap y.f ();//
call
yp->f () directly with object
;
The main object is to call the function f and the assembly code using the pointer to call function f:
The assembly code that invokes function f directly with the object:
; : Y.f ();
Lea ecx, DWORD PTR _Y$[EBP]; give ECX the first address of the object y created on the stack, passed as an implied parameter to F call? f@y@ @UAEXXZ ;
Use the pointer to invoke the assembly code of function F indirectly:
; Num : Yp->f ();
MOV ecx, DWORD ptr _YP$[EBP]; the first address of the heap object to which the YP pointer is directed to ECX
mov edx, DWORD ptr [ECX]; the contents of the object created on the heap are directed to edx Vtable the first address of the vptr pointer to edx
mov ecx, DWORD PTR _YP$[EBP]; Pass the first address of the heap object pointed to by the YP pointer to ECX as a suppressed parameter to the function f mov to invoke eax, DWORD PTR [Edx];edx is the vtable first address, here take the contents of the vtable first address to eax the address of function f to
eax call eax; invoke EAX
From the sink code can be seen, the object of direct call when there is no access to the virtual table vtable, only when the pointer calls to access the vtable, forming a late bundle. Because the compiler already knows the exact type of object, in order to increase efficiency, when invoking these virtual functions, a build bundle is used.
Inheritance and vtable
When a subclass inherits the parent class, the compiler creates a vtable for the subclass, and the virtual function in the parent class Vatelbe exactly in the same position in the subclass vtable, and the virtual function that is redefined in the subclass inserts its address at the new location in the subclass vtable.
The following is the C + + Source:
Class X {
private:
int i;
Public:
virtual void A () {
i = 1;
}
virtual void B () {
i = 2;
}
};
Class Y:public X {
private:
int i;
Public:
virtual void C () {//Newly defined virtual function
i = 3;
}
void B () {//overriding the virtual function in the parent class
i = 4;
}
;
int main () {
x* XP = new X;
x* YP = new Y;
Xp->a ();
Xp->b ();
Yp->a ();
Yp->b ();
Yp->c (); Compiler Error
}
You can see that the virtual function C in the subclass is called with the YP Pointer, and the compiler complains. This is because although the type of timing pointed to by the YP pointer is subclass Y, but because it is converted up to the base class X type, the compiler only targets the base class at compile time, and the base class has only virtual function a,b, so it is not allowed to invoke the virtual function C in the subclass.
Only the assembly code that invokes the virtual function is given below:
;
28:xp->a (); mov edx, DWORD ptr _XP$[EBP]; the first address of the heap object to which XP is directed to EDX mov eax, DWORD ptr [edx]; the contents of the heap object's first address are given to eax, and the vptr to the first address of Vtable point to EAX mov ECX, DWORD ptr _XP$[EBP]; give ECX the first address of the heap object that XP points to, as an implied parameter to the virtual member function that is about to be called mov edx, DWORD ptr [EAX]; give vtable the contents of the edx's first address, and give the address of the virtual function a EdX (here, the address of virtual function A is located at the vtable first address of the parent class X) call edx; Calling virtual member function A;
29:xp->b (); mov eax, DWORD ptr _XP$[EBP]; give the first address of the heap object of XP to EAX mov edx, DWORD ptr [EAX]; the contents of the heap object's first address to edx, and the vptr to the first address of Vtable point to EDX mov EC X, DWORD ptr _XP$[EBP]; give the first address of the heap object of XP to ECX mov eax, DWORD ptr [edx+4]; 4byte the memory content of the offset vtable to eax, the address of the virtual function B to eax (here, the address of virtual function B) At the vtable first address at 4byte of the offset parent class X) call eax; invoke virtual member function B;
30:yp->a (); mov ecx, DWORD ptr _YP$[EBP]; the first address of the heap object to which YP is directed to ECX mov edx, DWORD ptr [ECX]; the contents of the heap object's first address are given to edx, and the subclass Vptr to the vtable of the first address to the EDX mov ECX, DWORD ptr _YP$[EBP]; give ECX the first address of the heap object pointed to by YP, pass it to the virtual member function a mov eax as implied parameter, DWORD ptr [edx]; give vtable the contents of the subclass EAX at the first address, and give the address of virtual function A to EA X (here, the address of virtual function A is also located at the vtable first address of subclass y) call eax; Calling virtual member function A;
31:yp->b (); mov ecx, DwoRD PTR _YP$[EBP]; gives the first address of the heap object that YP points to ECX mov edx, DWORD ptr [ECX], the contents of the heap object's first address to edx, and the subclass Vptr pointed vtable to edx mov ecx, DWORD PTR _YP$[EBP]; give ECX the first address of the heap object that the YP points to, pass to the virtual member function B mov eax as the implied parameter, DWORD ptr [edx+4], and vtable the contents of the memory at the first address 4byte of the offset subclass EAX. The address of the virtual function B is given to EAX (here, the address of virtual function B is also located at the vtable address 4byte of the offset subclass y) call eax; invoke virtual member function B; ://yp->c ();
As you can see from the remit encoding, the a,b virtual function is the same position in the subclass Vtable and the parent class table (as can be seen from the offset of their vtable). This ensures that the compiler always uses the same offset to invoke the virtual function, regardless of the object's actual type. If you don't do this, that is, the position of the virtual function a,b in the vtable of the subclass Y is not the same as the position in the vtable of the parent class X, because of the upward transformation, the compiler works only for the parent class, that is, the call to the virtual function a,b only determines the offset based on the vtable of the parent class Then the actual operation of the time will be wrong, the actual child objects can not call the correct function, polymorphic failure.
In the example above, if you convert YP to the actual type call C, we see that the compiler has an offset of 8byte, and the assembly code is as follows:
; : yp->c ();
MOV ecx, DWORD ptr _YP$[EBP]; the first address of the heap object to which the YP is directed to ECX
mov edx, DWORD ptr [ECX]; the contents of the heap object's first address are given to edx. Vtable the first address of the subclass vptr to edx
mov ecx, DWORD PTR _YP$[EBP], and the first address of the heap object to YP, which is passed to the virtual member function as the implied parameter C
mov ecx, DWORD PTR [edx+8]; vtable the contents of the memory at the first address 8byte of the offset subclass to EAX, the address of the virtual function C to eax (here, the address of the virtual function B is also located at the vtable at the beginning address 8byte of the offset subclass y) Call EAX, calling virtual member function c
Object slices
If the upward transition is not to use the address or reference, but with the value, then the object slice, that is, the derived class objects are partially removed, only the base class part.
The following is the C + + Source:
Class X {
private:
int i;
Public:
virtual void A () {
i = 1;
}
virtual void B () {
i = 2;
}
};
Class Y:public X {
private:
int i;
Public:
virtual void C () {//Newly defined virtual function
i = 3;
}
void B () {//overriding the virtual function in the parent class
i = 4;
}
;
void f (x x) {//Convert up x.b () in the form of a pass value
);
int main () {
y y;
f (y);
}
The following is the assembly code for the main function:
; int main () {
push ebp
mov EBP, esp
Sub ESP, 16byte space reserved for object y
; y y;
Lea ecx, DWORD PTR _Y$[EBP]; give the first address of Y to ecx, to the constructor called "Pass to the Y" by the implied parameter. 0y@ @QAE @xz; The constructor that calls Y; f (y)
; Sub ESP, 8;//because of the value of the object, to copy, to produce a temporary object, here for temporary objects reserved 8byte space (class x size)
mov ecx, esp;//the temporary object's first address to ECX, Pass to copy function as implied parameter
Lea eax, DWORD PTR _Y$[EBP]; give the first address of the object Y to eax as a parameter to push EAX to the copy function ; Press stack, pass parameter call ?? 0x@ @QAE @abv0@@z; Call the copy function of class
x f@ @YAXVX @@@z ; Call function f
add esp, 8; free 8byte space occupied by temporary objects just now
; £ º
xor eax, eax
mov ESP, ebp
pop ebp
ret 0
As you can see from the assembly, the size of the temporary object is the size of the parent class X, and the copy function of the call is also the copy function of the parent class X.
The following is the copy function sink encoding for the parent class X:
?? 0x@ @QAE @abv0@@z PROC ; X::x, comdat
; _this$ = ecx
push ebp
mov EBP, esp
push ecx; Press stack, reserve 4byte space mov for the first address of a stored object DWORD ptr _this$[ebp], ecx;ecx the first address of the temporary object, put to the space just reserved
mov eax, DWORD ptr _this$[ebp]; give the first address of the temporary object to ECX
mov DWORD PTR [eax], OFFSET?? _7x@@6b@ the vtable first address of Class X to the memory that the first address of the temporary object points to is the vptr pointer mov ecx that initializes the temporary object , and the DWORD PTR _THIS$[EBP]; give the first address of the temporary object to ECX
MOV edx, DWORD ptr ___THAT$[EBP]; the first address of Y is given to edx
mov eax, DWORD ptr [EDX+4]; the memory content at 4byte at the beginning of the Y address is given to edx. The value of the member variable I in the parent object that is included in Y is given to edx
mov DWORD PTR [ecx+4], eax; the EAX value to offset the 4byte memory at the first address of the temporary object, the value of the EAX to the member variable of the temporary object I
mov eax, DWORD PTR _THIS$[EBP]; give the first address of the temporary object to EAX as the return value. The constructor always returns the first address of the object mov esp, ebp
pop ebp
ret 4
As you can see from the copy function, the temporary object copies only the part of the parent object that y contains (y is sliced), and the vptr pointer of the temporary object is also initialized to the vtable first address of Class X.
The following is the assembly code for function F:
; : void f (x x) {
push ebp
mov EBP, esp : x.b ();
Lea ecx, DWORD PTR _X$[EBP]; give the first address of the parameter x to ECX as an implied parameter to the member function B call? b@x@ @UAEXXZ ; Calling member function B in X This is called directly with the object, so there is no access to the vtable
This calls the member functions inside Class X and does not have access to the virtual table vtable
Here is the assembly code for the virtual member function B inside class X:
b@x@ @UAEXXZ PROC ; X::b, comdat
; _this$ = ecx
; 8 : virtual void B () {
push ebp
mov EBP, esp
push ecx; reserved 4byte space mov DWORD PTR _this$[ebp for saving object first address, ecx;ecx The first address of object X, put to the space that just reserved
; 9 : i = 2;
mov eax, DWORD ptr _this$[ebp]; give x first address to EAX
mov DWORD ptr [eax+4], 2; Write 2 to offset x address 4byte, 2 to X's member variable i
; A:
mov ESP, ebp
pop ebp
ret 0
? b@x@ @UAEXXZ ENDP
The above article from the compilation of C + + in the polymorphic explanation is small series to share all the content of everyone, hope to give you a reference, but also hope that we support the cloud-dwelling community.