// From http://en.cppreference.com/w/cpp/language/virtual
//
// Build with:        g++ -Wall -o ovl ovl.cc
// Disassemble with:  objdump -d ovl  OR  gobjdump -d ovl

#include <iostream>

struct Derived; // this so-called "forward declaration" is needed for the last foo(Derived*) variant to compile

struct Base {
    int a = 0, b = 0 , c = 0;

     virtual void foo() {
          std::cout << "base\n";
     }

     // Let's add some overloading!

     virtual void foo(int x) {
          std::cout << "base overloaded\n";
     }

     virtual void foo(Base *q){
          std::cout << "base overloaded too\n";
     }

     virtual void foo(Derived *q){
          std::cout << "base overloaded even more\n";
     }

     // what happens if you change the return value type? Can you guess why?
};

// every object of type Derived includes Base as a subobject
struct Derived : Base {
    int b = 1;

     void foo() { // OR: void f() override { // 'override' is optional
          std::cout << "derived\n";
     }
};

int main()
{
     Base b;
     Derived d;
     
     Base*    bp = &b; // 
     Derived* dp = &d; // Try this with Base* first, notice where the output differs---and doesn't!
     bp->foo();        //   prints "base"
     dp->foo();        //   prints "derived"

     // Calling a method of an object through the base class pointer.  
     bp = (Base *) &d;
     bp->foo();        // <----- this is the heart of C++ inheritance-based OO!  
     
     std::cout << "member b via ptr: " << bp->b << " " << dp->b << std::endl;

     return 0;
}

