#include <iostream>
#include <string>

struct base {
   virtual ~base( ) = default;
   virtual void f( ) {
      std::cout << "f de base\n";
   }
};

struct derivado1 : base {
   int n = 123;

   virtual void f( ) {
      std::cout << "f de derivado1\n";
   }
};

struct derivado2 : base {
   char c = '@';

   virtual void f( ) {
      std::cout << "f de derivado2\n";
   }
};

struct derivado3 : derivado1 {      // un nivel de herencia más profundo: derivado3 hereda de derivado1 y derivado1 hereda de base
   std::string s = "hola";

   virtual void f( ) {
      std::cout << "f de derivado31\n";
   }
};

int main( ) {
   derivado1 d1;
   derivado2 d2;
   derivado3 d3;
   base* arr[4] = { nullptr, &d1, &d2, &d3 };      // dejo la posición 0 inutilizada para que d1 esté en [1], d2 esté en [2] y d3 esté en [3]

   int indice;
   std::cin >> indice;
   base* p = arr[indice];

   if (auto checar = dynamic_cast<derivado1*>(p); checar != nullptr) {
      std::cout << "Compatible con derivado1: " << checar->n << "\n";
   }
   if (auto checar = dynamic_cast<derivado2*>(p); checar != nullptr) {
      std::cout << "Compatible con derivado2: " << checar->c << "\n";
   }
   if (auto checar = dynamic_cast<derivado3*>(p); checar != nullptr) {
      std::cout << "Compatible con derivado3: " << checar->n << " " << checar->s << "\n";
   }

   if (typeid(*p) == typeid(derivado1)) {
      auto q = dynamic_cast<derivado1*>(p);
      std::cout << "Es exactamente un derivado1: " << q->n << "\n";
   }
   if (typeid(*p) == typeid(derivado2)) {
      auto q = dynamic_cast<derivado2*>(p);
      std::cout << "Es exactamente un derivado2: " << q->c << "\n";
   }
   if (typeid(*p) == typeid(derivado3)) {
      auto q = dynamic_cast<derivado3*>(p);
      std::cout << "Es exactamente un derivado3: " << q->n << " " << q->s << "\n";
   }
}
