could someone explain what is meant when they say that overloading occurs at compile time whereas overriding occurs at runtime? My understanding is overloading occurs within a class where a method's name is the same but the parameters differ. The return type may or may not be different. Overriding occurs between classes, or more specifically, between a super class and a descendant. Here the signature must match. Polymorphism occurs between classes that are descendants of the same super class. Here the return and the parameters are the same but the implementation is different
Why are same method names within a class resolved at compile time and same method names between classes resolved at runtime?
Given the following code...
Class Base
Method Example(char x)
Method Example(int x)
Base inst = NEW Base
inst.Example(1)
The compiler will see those methods as distinct methods because their signatures make them uniquely identifiable. So it knows the method call will go to the 2nd method in the class.
But things are a little more complicated than that because of subclasses...
Class Base
Method Example(char x)
Method Example(int x)
Class Ext1 Extends Class Base
Method Example(char x)
Class Ext2 Extends Class Base
Method Example(int x)
Base inst = NULL
if (something) {
inst = NEW Base
} else if (something_else) {
inst = NEW Ext1
} else {
inst = NEW Ext2
}
inst.Example(1)
Now although the compiler can still work out that the Example method which takes an int will be called at compile time, it cannot know which of the 3 classes will have been created, so it doesn't know the actual concrete method that will be called
This is where the vtable comes in. Taking the first example again but simulating how a vtable gets involved...
Class Base
VTable[0] = Method Example(char x)
VTable[1] = Method Example(int x)
Base inst = NEW Base
inst.VTable[1](1)
The compiler has turned what looks to us like a direct method call into an indirect call via the vtable. It is this method lookup process that allows overriding to work...
Class Base
VTable[0] = Method Example(char x)
VTable[1] = Method Example(int x)
Class Ext1 Extends Class Base
VTable[0] = Method Example(char x)
Class Ext2 Extends Class Base
VTable[1] = Method Example(int x)
Base inst = NULL
if (something) {
inst = NEW Base
} else if (something_else) {
inst = NEW Ext1
} else {
inst = NEW Ext2
}
inst.VTable[1](1)
So whereas overloading can be handled at compile time, overriding happens at runtime thanks to the vtable.