Reputation: 5039
Pardon me if the question found silly to you. I am a newbie to c++ and I was studying rum time polymorphism. I want to know what happens when base class object calls derived class function (which is non virtual). for example look at the code
class base {
public:
virtual void vfunc() {cout << "This is base's vfunc().\n";}
};
class derived1 : public base {
public:
void vfunc() {cout << "This is derived1's vfunc().\n";}
};
int main()
{
base *p, b;
derived1 d1;
p = &b;
p->vfunc();
p = &d1;
p->vfunc();
return 0;
}
I got the desired ouput, I then removed the virtual keyword from the base class and when I ran the program the output is
This is base's vfunc().
This is base's vfunc().
I will be very thankful if some one explain what happened (in terms of pointer manipulation) in both of the cases
Thanks
Upvotes: 2
Views: 1042
Reputation: 94820
In the virtual case, at runtime, p->vfunc()
tells p
to go to the class definition of the class (whatever part of it is in memory) that the pointee belongs to, and read its vtable (or some similar alternate implementation) to figure out which function to call.
Suppose the vtables look like below:
base
's vtable:
----------------
vfunc | 0x2048
----------------
derived1
's vtable:
----------------
vfunc | 0x2096
----------------
Then base version or derived version of vfunc
is called depending on where vtables point.
In non-virtual case, none of this happens, and the function to call is set in stone by the compiler at compile time. During compile time, all the compiler can figure out is that p
is of type 'pointer to base' and changes all the p->vfunc()
calls to point to address 0x2048
.
Upvotes: 2
Reputation: 15916
What's going on here is that there are two vtables, one for base and one for derived. In base's vtable you have one entry for vfunc()
, and in derived's vtable there is also one entry, the trick is when derived took it's parent's vtable it looked to see if it was overriding any of it's parent's virtual methods and it is. So it replaced what was there so that it now points to it's own version.
In other words, when you call vfunc()
through an instance of type base, you check the base vtable which contains a pointer to bases's vfunc()
. When you call it through an instance of derived, you find the pointer to derived's vfunc()
.
If you remove the virtual keyword, the compiler is no longer looking for a virtual function so instead of basing himself on the run time type of the object, it's basing itself on it's static/compile time type.
In other words, without the virtual keyword the compiler looks at the type of the pointer which is base, so it calls the base version, every time.
Upvotes: 1