Introduction
Since I wrote my first article on CodeProject, I was eager to post the second one but, I didn't have the time to write down my thoughts and ideas. Now that I have an opportunity to write I am jotting down my ideas. The topic that I am going to discuss is at the beginner level but is always puzzling for an amateur developer (Virtual Functions). I would like to have comments and ideas on how I could improve on this article and I would be highly thankful if you can point out any mistakes and inform me about them.
So let’s start…
First of all, let’s understand what a virtual function is and why is it needed. A virtual function allows you to achieve one kind of polymorphism where you can inherit a class from a Base
class and implement the function in the Derived
class. Based on the type of object that is contained in the base class pointer, the compiler decides at runtime which function to invoke. (TOO MUCH ! Ah) Let’s go into a little bit of detail: Suppose we have a base class that has a virtual function called fun and a constructor. Now what? Derive two classes from this Base
class and call them DerivedA
, DerivedB
. Implement the virtual function in both the classes. The code is as follows:
#include "stdafx.h"
#include <iostream />
using namespace std;
class Base
{
public :
Base()
{
cout<<"Constructor of Base"<<endl;
}
virtual void fun()
{
cout<<"In fun of Base class"<<endl;
}
};
class DerivedA:public Base
{
public:
DerivedA()
{
cout<<"Constructor of DerivedA"<<endl;
}
void fun()
{
cout<<"In fun of Derived A"<<endl;
}
};
class DerivedB:public Base
{
public:
DerivedB()
{
cout<<"Constructor of DerivedB"<<endl;
}
void fun()
{
cout<<"In fun of Derived B"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Base b;
DerivedA da;
DerivedB db;
return 0;
}
The output is:
Constructor of Base
Constructor of Base
Constructor of DervivedA
Constructor of Base
Constructor of DerivedB
Simple. Uptil now, we haven’t taken the virtual function and its implementation into account. We will do it now. Change the code of the main function to:
Base b;
DerivedA da;
DerivedB db;
b.fun ();
da.fun();
db.fun();
b=da;
b.fun ();
b=db;
b.fun ();
The output will be shown as:
Constructor of Base
Constructor of Base
Constructor of DervivedA
Constructor of Base
Constructor of DerivedB
In fun of Base class
In fun of Derived A
In fun of Derived B
In fun of Base class
In fun of Base class
The last two lines of output are shocking for the amateur programmers. Since we have assigned the derived class object to the base class, the implemented function in the derived classes should have been called. But this does not happen. Instead a phenomenon known as Object Slicing takes place.
Object Slicing:
#include "stdafx.h"
#include <iostream />
using namespace std;
class Base
{
int i,j;
public :
Base()
{
i=10;j=20;
cout<<"Constructor of Base"<<endl;
}
virtual void fun()
{
cout<<"In fun of Base class"<<endl;
cout<<i<<endl<<j;
}
};
class DerivedA:public Base
{
int k;
public:
DerivedA()
{
k=30;
cout<<"Constructor of DerivedA"<<endl;
}
void fun()
{
cout<<"In fun of Derived A"<<endl;
cout<<k;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Base b;
DerivedA d;
b=d;
b.fun ();
return 0;
}
Output:
Constructor of Base
Constructor of Base
Constructor of DervivedA
In fun of Base class
10
20
So we see that inspite of a derived class object being assigned to a base class object, we were not able to get the value of k of the derived class. The object of the derived class is larger as compared with the object of the base class. In other words, we can say that the base class object knows nothing about k, i.e., the object has been sliced. Now let us see how can we call the implemented functions of the derived class:
#include "stdafx.h"
#include <iostream>
using namespace std;
class Base
{
public :
Base()
{
cout<<"Constructor of Base"<<endl;
}
virtual void fun()
{
cout<<"In fun of Base class"<<endl;
}
};
class DerivedA:public Base
{
public:
DerivedA()
{
cout<<"Constructor of DerivedA"<<endl;
}
void fun()
{
cout<<"In fun of Derived A"<<endl;
}
};
class DerivedB:public Base
{
public:
DerivedB()
{
cout<<"Constructor of DerivedB"<<endl;
}
void fun()
{
cout<<"In fun of Derived B"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Base *b=new Base();
DerivedA da;
DerivedB db;
b->fun ();
b=&da;
b->fun();
b=&db;
b->fun ();
return 0;
}
Output:
Constructor of Base
Constructor of Base
Constructor of DervivedA
Constructor of Base
Constructor of DerivedB
In fun of Base class
In fun of Derived A
In fun of Derived B
The other day I was asked a question about which of the two statements would work?
Base *b=new DerivedA();
Derived *d=new Base();
I implicitly answered the first one would work and the second one would fail as a pointer of Derived
class could not be typecasted to that of the base class implicitly. To make this thing work, we would have to write:
Base *b=new DerivedA();
DerivedA *d=reinterpret_cast<deriveda* />(new Base());
To see the change of how the functions are called, change the code in the main function of the above example to:
Base *b=new DerivedA();
DerivedA *d=reinterpret_cast<DerivedA*>(new Base());
b->fun();
d->fun();
Output:
Constructor of Base
Constructor of DervivedA
Constructor of Base
In fun of DerivedA
In fun of Base class
Let’s do everything once with pointers:
#include "stdafx.h"
#include <iostream />
using namespace std;
class Base
{
public :
Base()
{
cout<<"Constructor of Base"<<endl;
}
virtual void fun()
{
cout<<"In fun of Base class"<<endl;
}
};
class DerivedA:public Base
{
public:
DerivedA()
{
cout<<"Constructor of DerivedA"<<endl;
}
void fun()
{
cout<<"In fun of Derived A"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Base *b=new Base();
DerivedA *da=new DerivedA();
b->fun ();
da->fun();
b=da;
b->fun ();
return 0;
}
Output:
Constructor of Base
Constructor of Base
Constructor of DervivedA
In fun of Base class
In fun of DerivedA
In fun of DerivedA
After having discussed so much about virtual functions, we haven’t even mentioned about VPTR
and the VTABLE
. Oh! This topic is endless… So here’s a description of VPTR
and VTABLE
for you. What’s a vptr
? The vptr
is a pointer which is the very data member of a class and can be accessed using the this
pointer. ( I will just show this in a while). Vptr
holds the address of the virtual table of the class thereby associating an object with virtual table. There is always a VTABLE
created for a class having a virtual function and each of the classes that are derived from it. Where does the vptr
reside and how can we invoke a function using this pointer? Now it’s the time to fulfill my promises that I made earlier in the article.
class Base
{
public:
virtual void __cdecl fun(int q)
{
cout<<"Hello Base : "<<endl<<q<<endl;
}
void CallVirtualFnUsingThis()
{
int *p=(int *)this;
cout<<"Address of Object : "<<*p<<endl;
p=(int *)*p;
cout<<"Address of VPTR : "<<p<<endl;
p=(int *)*p;
cout<<"Address of First Virtual Function in VTABLE : "<<p<<endl;
void (__cdecl *pfun)(Base* const,int);
pfun=(void(__cdecl*)(Base* const,int))p;
(*pfun)(this,25);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Base b;
b.CallVirtualFnUsingThis();
return 0;
}
And the output:
Address of Object : 4514088
Address of VPTR : 0044E128
Address of First Virtual Function in VTABLE :0041A0D6
Hello Base :
25
Comments
Any suggestions for the improvement of this article are most welcome. I would appreciate if you could read this article and rate it. That's all for now. I will update this article to add some images for showing how vptr
and vtable
are shown in memory.
History
- 6th July, 2006: Initial post