I understand why the virtual keyword is needed for overriding when objects of subclasses are dynamically created but, in the following example, why is late binding needed (virtual keyword) to override? Can't the compiler tell at compile time that pa is pointing to a derived class?
class A {
public: int f() { return 'A';}
};
class B : public A {
public: int f() { return 'B';}
};
int main() {
//I understand this case, since pa is pointing to
//something created at runtime, virtual keyword is needed
//to return 66
A* pa;
pa = new B;
cout << pa->f() << endl; //returns 65
//But why in this case where b2 is created during
//compile time, compiler doesn't know pa is pointing
//to a derived class?
B b2;
pa = &b2;
cout << pa->f() << endl; //returns 65
}
This question really does not revolve around whether the compiler can "know" or not the precise type of object pa
refers to. It revolves around the semantics of C++.
When you declare a method f
, you are telling the compiler how you want a call to f
to be handled. In the case that A::f
is not declared virtual
, you are saying that if pa->f()
is called and pa
has the declared type of A*
, you want the compiler to use the definition in A::f
. Certainly, *pa
is an object of type A
, even though it might also be an object of some derived type of A
.
If, on the other hand, you declare f
to be virtual
, you are telling the compiler that you want it refer to the most derived type of the object currently pointed to by pa
, and use the definition of f
from that type (or its appropriate supertype).
The semantics of C++ need to be deterministic. That is, you as the programmer need to be able to predict which definition of f
will be used in any given circumstance. If you think about it, it would be really difficult to program in a language with a rule which states "use B::f
if you happen to be able to figure out that pa
points to an object of type B
, but use A::f
if you are not sure what pa
points to". How hard should the compiler try to figure out what pa
points to? If in the future, someone in the compiler team figures out how to make a more accurate determination, should the semantics of your program magically change? Would you be happy with that?
Note that it is actually quite possible in both of the snippets you present that the compiler can figure out what the type of the object pointed to by pa
is. So even if f
were virtual
, an optimising compiler could well omit the code to look up the correct method in the vtable, and just call the correct method directly. Nothing in the C++ standard prohibits such an optimisation, and I believe that it is quite common. So if in the future someone in the compiler team figures out a better way of determining the type of a variable, it will not change the semantics of your program -- it will still invoke the same method. But it might result in your program invoking your method more quickly. That is an outcome which is much more likely to make the future you happy.