/*
 * 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>
#include <memory>
#include <vector>

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

// A small polymorphic hierarchy so dynamic_cast has something to check.
class Shape {
 public:
  virtual ~Shape() {}
  virtual double Area() const = 0;  // pure virtual -> Shape is abstract
};

class Circle : public Shape {
 public:
  explicit Circle(double r) : r_(r) {}
  double Area() const override { return 3.14159 * r_ * r_; }
  void Roll() const { cout << "  (a circle can roll)" << endl; }

 private:
  double r_;
};

class Square : public Shape {
 public:
  explicit Square(double s) : s_(s) {}
  double Area() const override { return s_ * s_; }

 private:
  double s_;
};

int main(int argc, char** argv) {
  // ---- static_cast: compile-time numeric conversion (slide 34) ---------
  double d = 3.9;
  int n = static_cast<int>(d);  // 3: truncates, says what it means
  cout << "static_cast<int>(3.9) = " << n << endl;

  // ---- dynamic_cast: run-time CHECKED down-cast (slide 34) -------------
  std::vector<std::unique_ptr<Shape>> shapes;
  shapes.push_back(std::make_unique<Circle>(2.0));
  shapes.push_back(std::make_unique<Square>(3.0));

  for (const auto& shape : shapes) {
    cout << "Area = " << shape->Area();
    // Is this Shape really a Circle?  Ask at run time.
    Circle* c = dynamic_cast<Circle*>(shape.get());
    if (c != nullptr) {
      cout << "  -> it is a Circle:" << endl;
      c->Roll();  // safe: it really is one
    } else {
      cout << "  -> not a Circle" << endl;
    }
  }

  return EXIT_SUCCESS;
}