The following program is adapted from instrument4.cpp of thinking in C ++.
# Include <iostream> <br/> using namespace STD; <br/> Enum note {middlec, CSHARP, cflat}; // etc. <br/> class instrument {<br/> Public: <br/> virtual void play (Note) const {<br/> cout <"instrument :: play "<Endl; <br/>}< br/> virtual char * What () const {<br/> return" instrument "; <br/>}< br/> // assume this will modify the object: <br/> virtual void adjust (INT) {}< br/> }; <br/> class wind: public instrument {<br/> Public: <br/> void play (Note) const {<br/> cout <"Wind :: play "<Endl; <br/>}< br/> char * What () const {return" wind ";}< br/> void adjust (INT) {}< br/> void print () {<br/> cout <"hello" <Endl; <br/>}< br/> }; <br/> int main () {<br/> wind * w = new wind; <br/> W-> Print (); <br/> W-> what (); <br/> return 0; <br/>}
The disassembly process for calling the virtual function w-> wind () is as follows:
W-> what (); <br/> 80366f6: 8B 45 F4 mov-0xc (% EBP), % eax <br/> 80366f9: 8B 00 mov (% eax ), % eax <br/> 80366fb: 83 C0 04 add $0x4, % eax <br/> 80366fe: 8B 10 mov (% eax ), % edX <br/> 8048800: 8B 45 F4 mov-0xc (% EBP), % eax <br/> 8048803: 89 04 24 mov % eax, (% ESP) <br/> 8048806: FF D2 call * % edX <br/>
Explanation:
Begin
W = 0x97b1008
& W = 0xbfab8bbc
* W = 0x80489f0
Mov-0xc (% EBP), % eax
% Eax = W = 0x97b1008
Is a pointer. Like this, it points to the first address of the wind object, and also to the vptr of the wind object.
MoV (% eax), % eax
% Eax = vptr = * w = 0x80489f0
At this time, % eax stores vptr. Initially, vptr points to the first address of the vtable.
Add $0x4, % eax
% Eax = vptr + 4 = 0x80489f4
Add vptr to 4 to point to the second entry of vtable. The second entry stores the first address of the second virtual function.
MoV (% eax), % edX
% EdX = * (vptr + 4) = 0x8048828
Obtain the first address of the second virtual function and store it in the register % EDX.
Mov-0xc (% EBP), % eax
MoV % eax, (% ESP)
To hide the parameter W, we can also say that this is the pressure stack.
Call * % edX
Call the second virtual function, that is, what () of the wind object ()
After W-> wind () is called, The system resets the vptr value and points it back to the first vtable address.
The above program uses a pointer from a derived class to call a virtual function. What if it uses a base class pointer to call a virtual function? See the following example:
Wind * w = new wind; <br/> instrumeng * I = W; <br/> I-> what ();