C++ Virtual Functions Disassembled

Virtual Function Table
I assume the following definitions (remember that a is defined as a class with default  access): struct Base { Base : x(4) {} virtual int get_value { return x; } int x;                                }; struct Derived : public Base { int get_value { return 2 * x; } };                   ... Base b; Derived d;                             Base *dp = &d; // pointer (upcasted) Base &dr = d; // reference (upcasted) Each class with virtual member functions has a static virtual function table containing pointers to each virtual member function for that class. Each object has a Vtable pointer, which points to the Vtable of its class after initialization

To inspect the Vtables with, you can use: g++ -fdump-class-hierarchy program.cpp This creates a new file : Vtable for Base Base::_ZTV4Base: 3u entries 0    0u                            // ? (some sort of offset) 4    (int (*)(...))(&_ZTI4Base)    // Base typeinfo 8    Base::get_value Class Base size=8 align=4 base size=8 base align=4 Base (0xb7d20800) 0 vptr=((&Base::_ZTV4Base) + 8u) // vptr = address of first function //       in Vtable Vtable for Derived Derived::_ZTV7Derived: 3u entries 0    0u                            // ? (some sort of offset) 4    (int (*)(...))(&_ZTI7Derived) // Derived typeinfo 8    Derived::get_value Class Derived size=8 align=4 base size=8 base align=4 Derived (0xb7d20e00) 0 vptr=((&Derived::_ZTV7Derived) + 8u) // vptr = address of first Base (0xb7d20e40) 0                   //        function in Vtable primary-for Derived (0xb7d20e00) This is the Vtable generated for  by , in assembler code: .weak  _ZTV4Base .section       .gnu.linkonce.r._ZTV4Base,"a",@progbits .align 8 .type  _ZTV4Base, @object .size  _ZTV4Base, 12 _ZTV4Base:                           ; class Base Vtable .long  0                     ; ? (some sort of offset) .long  _ZTI4Base             ; Base typeinfo (defined elsewhere) .long  _ZN4Base9get_valueEv  ; Base::get_value And the Vtable generated for : .weak  _ZTV7Derived .section       .gnu.linkonce.r._ZTV7Derived,"a",@progbits .align 8 .type  _ZTV7Derived, @object .size  _ZTV7Derived, 12 _ZTV7Derived:                          ; class Derived VTable .long  0                       ; ? (some sort of offset) .long  _ZTI7Derived            ; Derived typeinfo (defined elsewhere) .long  _ZN7Derived9get_valueEv ; Derived::get_value The Derived constructor: .section       .gnu.linkonce.t._ZN7DerivedC1Ev,"ax",@progbits .align 2 .weak  _ZN7DerivedC1Ev .type  _ZN7DerivedC1Ev, @function _ZN7DerivedC1Ev: pushl  %ebp                    ; save caller base pointer movl   %esp, %ebp              ; define callee base pointer ; push 'this' to stack: subl   $4, %esp                ;   allocate 1 word on stack for 'this' movl   8(%ebp), %eax           ;   copy 'this' to eax movl   %eax, (%esp)            ;   ... and from there to top of stack call   _ZN4BaseC2Ev            ; call Base::Base (non-static member                                         ;   functions always use 'this' as an                                         ;   implicit first argument) movl   8(%ebp), %eax           ; copy 'this' to eax movl   $_ZTV7Derived+8, (%eax) ; copy Derived Vtable to 'this' ;  i.e. store Vtable in first attribute ;  of 'this' (vptr). Note that the ;  vptr points to the first function, ;  Derived::get_value leave                          ; restore caller stack frame ret                            ; return to caller .size  _ZN7DerivedC1Ev, .-_ZN7DerivedC1Ev

Invocation
Non-virtual method call : leal   -16(%ebp), %eax         ; copy pointer to 'd' in eax movl   %eax, (%esp)            ; ... and from there to top of stack call   _ZN7Derived9get_valueEv ; call Derived::get_value with ;  pointer to 'd' as implicit first ;  argument Virtual method call : movl   -20(%ebp), %eax         ; store pointer to 'd' in eax movl   (%eax), %edx            ; copy vptr (first element of 'd') to                                         ;   edx movl   -20(%ebp), %eax         ; store pointer to 'd' in eax (again) movl   %eax, (%esp)            ; ... and from there to top of stack movl   (%edx), %eax            ; copy first element in Vtable ;  (Derived::get_value) to eax call   *%eax                   ; call Derived::get_value

Performance
Obviously, there is a small performance issue with virtual methods. If you do high-performance applications, note that this example performs perfectly in the time domain (although not in the space domain): struct Thing { virtual ~Thing {} virtual int method = 0; }; struct Thing2 : public Thing { int method { return 10; } // note: not virtual }; int main { Thing2 thing; return thing.method; } The 'main' code, when optimized, resolves to: main: pushl  %ebp movl   $10, %eax movl   %esp, %ebp popl   %ebp ret Which is equivalent to: int main { return 10; } If we did: int main { Thing2 thing2; Thing & thing = thing2; return thing.method; } We would have the usual virtual method overhead.