Difference between calling of virtual function and non virtual function?

浪子不回头ぞ 提交于 2019-12-30 03:11:27

问题


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.


回答1:


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




回答2:


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




回答3:


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




回答4:


The overhead of calling a virtual method is significant.

Also this.




回答5:


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



来源:https://stackoverflow.com/questions/8776507/difference-between-calling-of-virtual-function-and-non-virtual-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!