分类: C/C++
2011-03-30 21:42:53
Virtual Functions
What is a Virtual Function?
A virtual function is a member function of a class, whose functionality can be over-ridden in its derived classes. It is one that is declared as virtual in the base class using the virtual keyword. The virtual nature is inherited in the subsequent derived classes and the virtual keyword need not be re-stated there. The whole function body can be replaced with a new set of implementation in the derived class.
What is Binding?
Binding refers to the act of associating an object or a class with its member. If we can call a method fn() on an object o of a class c, we say that the object o is binded with the method fn(). This happens at compile time and is known as static or compile - time binding. The calls to the virtual member functions are resolved during run-time. This mechanism is known as dynamic binding. The most prominent reason why a virtual function will be used is to have a different functionality in the derived class. The difference between a non-virtual member function and a virtual member function is, the non-virtual member functions are resolved at compile time.
How does a Virtual Function work?
Whenever a program has a virtual function declared, a v - table is constructed for the class. The
v-table consists of addresses to the virtual functions for classes that contain
one or more virtual functions. The object of the class containing the virtual
function contains a virtual pointer that points to the base address of the
virtual table in memory. Whenever there is a virtual function call, the v-table
is used to resolve to the function address. An object of the class that
contains one or more virtual functions contains a virtual pointer called the
vptr at the very beginning of the object in the memory. Hence the size of the
object in this case increases by the size of the pointer. This vptr contains
the base address of the virtual table in memory. Note
that virtual tables are class specific, i.e., there is only one virtual table
for a class irrespective of the number of virtual functions it contains.
This virtual table in turn contains the base addresses of one or more virtual
functions of the class. At the time when a virtual function is called on an
object, the vptr of that object provides the base address of the virtual table
for that class in memory. This table is used to resolve the function call as it
contains the addresses of all the virtual functions of that class. This is how
dynamic binding is resolved during a virtual function call.
The
following code shows how we can write a virtual function in C++ and then use
the same to achieve dynamic or runtime polymorphism.
#include |
In the
above example, the pointer is of type base but it points to the derived class
object. The method display() is virtual in nature. Hence in order to resolve
the virtual method call, the context of the pointer is considered, i.e., the
display method of the derived class is called and not that of the base. If the
method was non virtual in nature, the display() method of the base class would
have been called.
What is Virtual Constructors and Destructors
A constructor cannot be virtual
because at the time when the constructor is invoked the virtual table would not
be available in the memory. Hence we cannot have a virtual constructor.
A
virtual destructor is one that is declared as virtual in the base class and is
used to ensure that destructors are called in the proper order. It is to be
remembered that destructors are called in the reverse order of inheritance. If
a base class pointer points to a derived class object and we some time later
use the delete operator to delete the object, then the derived class destructor
is not called. Refer to the code that follows:
#include |
In this
case the type of the pointer would be considered. Hence as the pointer is of
type base, the base class destructor would be called but the derived class
destructor would not be called at all. The result is memory leak. In order to
avoid this, we have to make the destructor virtual in the base class. This is
shown in the example below:
#include |
Conclusion:
Virtual
methods should be used judiciously as they are slow due to the overhead
involved in searching the virtual table. They also increase the size of an
object of a class by the size of a pointer. The size of a pointer depends on
the size of an integer. Note that in DOS based systems the size of a pointer is
2 bytes whereas in UNIX based systems it is 4 bytes.