Why virtual functions? And how to use them?
When compiler tries to interpret function calls in C or C++, it binds function names with the particular block of code to be executed. This binding happens at compiler time and termed static binding (or early binding).
However there are times when the types of objects or functions couldn’t be determined at compile time, therefore compiler has to generate code or do some extra processing to make correct function call at run-time, this is called dynamic binding (or late binding).
Virtual member functions are the C++ answer to dynamic binding.
Why having static binding then? (since dynamic binding solves all typing problems at run-time!). There are two reasons: efficiency and conceptual model.
Efficiency - for a program to be able to make a runtime decision, it has to have some way to keep track of what sort of object a base-class pointer or reference refers to, and that entails some extra processing overhead. The fact that static binding is more efficient is the reason it is the default choice for C++. You should therefore go to virtual function only if the program design needs them.
Conceptual model - when you design a class, you may have member functions that you don’t want redefined in derived classes. By making this function non-virtual, you accomplish two things, first you make it more efficient; second, you announce that it is your intention that this function not be redefined. That also suggests reserving the virtual label just for methods you expect to be redefined.
Rule of thumb: if a method in a base class will be redefined in a derived class, you should make it virtual. If the method should not be redefined, you should make it non-virtual.
Now comes to more interesting part: How is virtual function implemented by compiler? virtual function table (vtbl)
The usual way compilers handle virtual functions is to add a hidden member to each object. The hidden member holds a pointer to an array of function addresses.
Such an array is usually termed a virtual function table. The
vtbl holds the addresses of the virtual functions declared for objects of that class.
For example, an object of a base class contains a pointer to a table of addresses of all the virtual functions for that class. And object of derived class
contains a pointer to a separate table of addresses. If the derived class provides a new definition of a virtual function, the
vtbl holds the address of the new
function. If the derived class doesn’t redefine the virtual function, the
vtbl holds the address of the original version of that function. If the derived class
defines a new function and makes it virtual, its address is added to the vtbl.
As you can see, with this virtual function implementation, each (virtual) function call takes an extra step of going to a table to look up an address. Therefore it is less efficient than static binding but able to achieve dynamic binding.
Beginning a class method declaration with the keyword virtual in a base class makes a function virtual for the base class and all classes derived from the base class, including classes derived from the derived classes, and so on.
Destructors of a base class should be virtual. You should provide a base class with a virtual destructor, even if the class doesn’t need a destructor. The reason is, when you delete a derived object via a base-class pointer or reference to the object, the program uses the derived-class destructor followed by the base-class destructor rather than using only the base-class destructor.