问题
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
- fun(_ZN7Derived3funEv) override function
- fun1(_ZN4Base4fun1Ev) inherited from Base class
- 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