// Overloading versus Overriding in Object Oriented Programming class A { int f() { return 1; } } class B extends A { int f() { return 2; } // this is called OVERRIDING } public class overloadride { static int g(A x) { return 10; } static int g(B x) { return 20; } // this is OVERLOADING // OVERLOADING: Resolved by compiler using STATIC type information. // OVERRIDING: Resolved at runtime with dynamic type info (dynamic dispatch) public static void main(String[] args) { A n = new B(); // static type is A, dynamic type is B System.out.println(n.f()); // overriding (dynamic dispatch) calls B.f System.out.println(g(n)); //overloading, (static dispatch) calls g(A). // prints 2 then 10 } } /* Advanced object oriented programming requires dynamic type information and dynamic dispatch. an "A" object can either be an A object or a B object. For example, if we declared an array A[] N = { new A(), new B(), new A() }; What is the TYPE of N[i]? Is it A or B? That information does not exist until runtime, when the object is actually created (via 'new') and i is known. At compile time, the type of N[i] is A (superclass). So if the compiler is asked to resolve g(N[i]) it can only choose the version g(A x). The types of arguments to a function are always resolved statically, never dynamically. Dynamic dispatch occurs if we call A[i].f(); The version of f to call is not decided at compile time at all. The compiler only checks that some f exists. The choice as to which one to call is made at runtime using the dynamic type information associated with each object. In Java, dynamic dispatch occurs on "n.f()" for all functions f except ones that are static or private. */ /* C++ version #include using namespace std; struct A { virtual int f() { return 1; } // note "virtual" }; struct B : public A { int f() override { return 2; } // note "override" }; int g(A* x) { return 10; } int g(B* x) { return 20; } int main() { A* n = new B(); cout << n->f() << endl; // prints 2 (overloading = dynamic dispatch) cout << g(n) << endl; // prints 10 (overriding = resolved statically). } In C++, to have the default behavior of Java we must 1. use public inheritance to establish "is a" relationship between B and A 2. use the keywords "virtual" and "override" on functions 3. use dynamic memory allocation (as opposed to stack allocation) because the compiler doesn't know exact type and size of object to be created. Only classes that contain virtual/override methods will have dynamic type information attached to objects at runtime, and the objects must be allocated on the heap. */