13

This is in fact an interview question, I can't figure out the answer. Anyone knows about this? You can talk about any difference, for example, the data that are push into stack.

iammilind
  • 68,093
  • 33
  • 169
  • 336
cheng
  • 2,106
  • 6
  • 28
  • 36
  • What exactly is your question? – Cheers and hth. - Alf Jan 08 '12 at 09:21
  • 1
    A virtual function undergoes dynamic dispatch. You should pick [a good C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) to learn it better. – GManNickG Jan 08 '12 at 09:22
  • I think the question is a bit vague. What kind of difference does it mean? Difference on code semantics level, compiler level or machine level? – erenon Jan 08 '12 at 09:24

5 Answers5

30

Though virtualism/dynamic dispatch is strictly implementation defined, most(read all known) compilers implement it by using vptr and vtable.

Having said that, the difference between calling a non virtual function and virtual function is:

Non-virtual functions are resolved statically at Compile-time, While Virtual functions are resolved dynamically at Run-time.

In order to achieve this flexibility of being able to decide which function to call at run-time, there is an little overhead in case of virtual functions.

An additional fetch call that needs to be performed and it is the overhead/price you pay for using dynamic dispatch.

In case of non-virtual function the sequence of calls is:

fetch-call

The compiler needs to fetch address of the function and then call it.

While in case of virtual functions the sequence is:

fetch-fetch-call

The compiler needs to fetch the vptr from the this, then fetch the address of the function from the vptr and then call the function.

This is just a simplified explanation the actual sequence maybe far more complex than this but this is what you really need to know, One does not really need to know the implementation nitty gritty's.

Good Read:

Inheritance & Virtual Functions

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Can you provide more details about the process of fetch-call and fetch-fetch-call? Or can you provide some readings? Thanks. – cheng Jan 08 '12 at 09:27
  • 1
    @cheng: Added a link, which provides a good explanation of the details. – Alok Save Jan 08 '12 at 09:31
  • It might be worth considering the effect on caching and pipelining and memory locality that the extra level of indirection has. What looks simple on paper may have non-negligible effects in practice. – Kerrek SB Jan 11 '12 at 16:35
  • The sequence for a non-virtual function is `call`. The sequence for a function pointer is `fetch-call`. A vtable adds another `fetch`. – MSN Jan 11 '12 at 18:01
  • Hi Alok, Just one improvement to the answer, Compiler fetch the vptr from object instead of this. this coming to the picture after calling the member function – Ajay yadav Dec 25 '15 at 11:05
8

If you have a base class 'Base' and derived class 'Derived' and you have a function 'func()' defined as virtual in Base class. This func is overridden by the Derived class.

Suppose you define

       Base obj = new Derived();
       obj.func();

Then the 'func' of Derived class is called. While if 'func()' was not defined as virtual in Base then it would be called from 'Base' class. This is the difference how the function calling differs for vitual and non-virtual functions

Shraddha
  • 2,337
  • 1
  • 16
  • 14
  • 2
    A few subtle points: 1. `obj` needs to be a pointer. 2. Apt to mention that the overidding function `Derived::func()` should take the same arguments to be overidding the `Base::func()` – Alok Save Jan 08 '12 at 09:35
  • 1
    It is not a subtle point, but a crucial one. "obj.func()" will not call the base class method but one has to use pointers and call "obj->func()" to make use of virtual methods. – 463035818_is_not_an_ai Apr 01 '15 at 11:24
  • Note that one can use references rather than pointers, though not always in the same situations. For instance, a reference cannot be rebound to refer to a different object. – Alan Jul 19 '16 at 14:47
4

Non-virtual member functions are resolved statically. member function are binding statically at compile-time based on the type of the pointer (or reference) to the object.

In contrast, virtual member functions are binding dynamically at run-time. If class have atleast one virtual member function then compiler puts a hidden pointer in the object called a vptr(virtual table address) during the construction of object.

The compiler creates a v-table for each class that has at least one virtual function. Virtual table contain virtual function's address. It can be array or list(depend upon the compiler) of virtual function pointer's
During a dispatch of a virtual function, the run-time system follows the object’s v-pointer(fetch the address from class object) to the class’s v-table, then offset is added to the base address(vptr) and call the function.

The space-cost overhead of the above technique is nominal: an extra pointer per object (but only for objects that will need to do dynamic binding), plus an extra pointer per method (but only for virtual methods). The time-cost overhead is also fairly nominal: compared to a normal function call, a virtual function call requires two extra fetches (one to get the value of the v-pointer, a second to get the address of the method).

None of this runtime activity happens with non-virtual functions, since the compiler resolves non-virtual functions exclusively at compile-time based on the type of the pointer.

I have taken simple example to understand in better manner, how the binding happened for non virtual function & virtual function and how virtual function mechanism works.

#include<iostream>
using namespace std;
class Base
{
        public:
                virtual void fun()
                {}
                virtual void fun1()
                {}

                void get()
                {
                        cout<<"Base::get"<<endl;
                }
                void get1()
                {
                        cout<<"Base::get1"<<endl;
                }
};

class Derived :public Base
{
        public:
                void fun()
                {
                }
                virtual void fun3(){}
                void get()
                {
                        cout<<"Derived::get"<<endl;
                }
                void get1()
                {
                        cout<<"Derived::get1"<<endl;
                }

};
int main()
{
    Base *obj = new Derived();
    obj->fun();
    obj->get();
}

How the vtable created for Base & derived class

Assembly code is generated for better understanding.

$ g++ virtual.cpp -S -o virtual.s

I have fetched the information of vtable from virtual.s for Base and Derived class respectively:

_ZTV4Base:
        .quad   _ZN4Base3funEv
        .quad   _ZN4Base4fun1Ev
_ZTV7Derived:
        .quad   _ZN7Derived3funEv
        .quad   _ZN4Base4fun1Ev
        .quad   _ZN7Derived4fun3Ev

As you can see fun & fun1 are only two virtual functions in Base class. Vtable of Base class(_ZTV4Base) have entries of both virtual functions. Vtable does not have entry of non-virtual function. Please do not confuse with name of fun(ZN4Base3funEv) & fun1(ZN4Base4fun1Ev), their name got mangled.

Derived class vtable have tree entries

  1. fun(_ZN7Derived3funEv) override function
  2. fun1(_ZN4Base4fun1Ev) inherited from Base class
  3. fun3(_ZN7Derived4fun3Ev) new function in derived class

How non virtual function & virtual function called?

for non-virtual function

    Derived d1;
    d1.get();

    subq    $16, %rsp
    leaq    -16(%rbp), %rax
    movq    %rax, %rdi
    call    _ZN7DerivedC1Ev //call constructor
    leaq    -16(%rbp), %rax
    movq    %rax, %rdi
    call    _ZN7Derived3getEv //call get function

Simply tell, fetch and call get(binding happened at compile time)

for non-virtual function

Base *obj = new Derived();
obj->fun();
pushq   %rbx
subq    $24, %rsp
movl    $8, %edi
call    _Znwm   //call new to allocate memory 
movq    %rax, %rbx
movq    $0, (%rbx)
movq    %rbx, %rdi
call    _ZN7DerivedC1Ev //call constructor
movq    %rbx, -24(%rbp)
movq    -24(%rbp), %rax
movq    (%rax), %rax
movq    (%rax), %rax
movq    -24(%rbp), %rdx
movq    %rdx, %rdi
call    *%rax //call fun

fetch the vptr, add the function offset, call the function(binding happened at run time)

Assembly of 64 is confusing most of c++ programmer but if any would like to discuss then welcome

Ajay yadav
  • 4,141
  • 4
  • 31
  • 40
3

When calling a virtual method, it has to look up which function to call in a virtual function table.

icktoofay
  • 126,289
  • 21
  • 250
  • 231
  • So what is the difference between calling a virtual function and non-virtual function? For example, how much memory access are necessary for each of them? – cheng Jan 08 '12 at 09:23
  • @cheng: I don't know how much more accesses virtual method calls have than non-virtual method calls have (I'd assume one or two), but virtual method calls do require a little more work. – icktoofay Jan 08 '12 at 09:26
  • OK, I will try to figure this out. Thank you. – cheng Jan 08 '12 at 09:30
  • 1
    The accepted answer provide a good reading about this problem. See above. – cheng Jan 08 '12 at 09:39
3

The overhead of calling a virtual method is significant.

Also this.