/*
 * Copyright ©2026 Soham Pardeshi. All rights reserved.
 * Permission is hereby granted to students registered for University of
 * Washington CSE 333 for use solely during Summer Quarter 2026 for
 * purposes of the course. No other use, copying, distribution, or
 * modification is permitted without prior written consent. Copyrights
 * for third-party components of this work must be honored. Instructors
 * interested in reusing these course materials should contact the author.
 */

#include <iostream>

using std::cout;
using std::endl;

// Demonstrates the two dispatch rules in one program (lecture 12 slide 26).
//   M1 is NON-virtual -> resolved by the POINTER's declared type (static).
//   M2 is virtual     -> resolved by the ACTUAL object       (dynamic).
class A {
 public:
  void M1() { cout << "a1, "; }          // static dispatch
  virtual void M2() { cout << "a2"; }    // dynamic dispatch
  virtual ~A() {}
};

class B : public A {
 public:
  void M1() { cout << "b1, "; }          // hides A::M1
  void M2() override { cout << "b2"; }   // overrides A::M2
};

int main(int argc, char** argv) {
  A obj_a;
  B obj_b;

  A* a_ptr_a = &obj_a;   // A* to an A
  A* a_ptr_b = &obj_b;   // A* to a B  <-- the interesting one
  B* b_ptr_b = &obj_b;   // B* to a B

  cout << "a_ptr_a: ";
  a_ptr_a->M1();  // a1,   (A* type)
  a_ptr_a->M2();  // a2    (object A)
  cout << endl;

  cout << "a_ptr_b: ";
  a_ptr_b->M1();  // a1,   M1 is static -> follows the A* pointer type
  a_ptr_b->M2();  // b2    M2 is virtual -> follows the actual B object
  cout << endl;

  cout << "b_ptr_b: ";
  b_ptr_b->M1();  // b1,   (B* type)
  b_ptr_b->M2();  // b2    (object B)
  cout << endl;

  return EXIT_SUCCESS;
}