Wednesday, February 08, 2006

remember the rule

sometimes its hard to figure out which method is called when looking at a hierarchy of classes, which use virtual specifier for their methods.

but, as always, if you know how the things works internally, you will always find the right answer.
I always think that instead of remembering 10 specific cases (which it might not be hard at all for many people, but me for example, I have a bad memory) its much easier to remember 1 thing only, how it works.

this is a case for the virtual specifier.
the thumb rule is this (this is from MSDN):
When calling a function using pointers or references, the following rules apply:
1.A call to a virtual function is resolved according to the underlying type of object for which it is called.
2.A call to a nonvirtual function is resolved according to the type of the pointer or reference.

but this rule might not be always simple to apply.
What is really good is to know why the things are happing like described in those 2 rules. Let's take each of them:
1. when you apply the virtual specifier to a function, at compile time, the compiler will do some things:
it will add an invisible vtable member ( a pointer to a table) to your class;
the vtable is initialized in constructor right after the base classes constructors are called (look here for construction order: this is a reason why when calling a virtual function in the constructor of a base class when creating an object of derived class, the virtual function is not called because the vtable is not initialized yet!)

also, its good to remember that there is only one vtable member in the derived class no matter how the big class hierarchy is and how many virtual functions are;

the term 'underlaying type' is used because you can always store inside a base object an a derived class object.

B b;
A *pa = &pb;

when you call pa->f() ( and f() is virtual declared in class A ) the vtable of the object points to the B::f() version, because the 'underlaying' type is B (i found the name confusing)

when we have an object A* we dont know if the object is an A or a B.
void function(A *pa)

2. if its not virtual then the function called is the one for the object class (the function is not in the vtable)

No comments: