#include <iostream>
#include <string>

struct figura {      // tipo vacío, sólo queremos usarlo como tipo base para habilitar el mecanismo virtual para un par de funciones
   virtual std::string nombre( ) const {
      return "";
   }

   virtual double perimetro( ) const {
      return -1;
   }
};

struct circulo : figura {        // heredamos de figura para aprovechar el mecanismo virtual
   double diametro;

   circulo(double d) {           // el uso de herencia normalmente nos obliga a declarar constructores
      diametro = d;
   }

   std::string nombre( ) const {
      return "circulo";
   }

   double perimetro( ) const {
      return 3.1416 * diametro;
   }
};

struct cuadrado : figura {       // heredamos de figura para aprovechar el mecanismo virtual
   double lado;

   cuadrado(double d) {
      lado = d;
   }

   std::string nombre( ) const {
      return "cuadrado";
   }

   double perimetro( ) const {
      return 4 * lado;
   }
};

struct rectangulo : figura {     // heredamos de figura para aprovechar el mecanismo virtual
   double base, altura;

   rectangulo(double b, double a) {
      base = b;
      altura = a;
   }

   std::string nombre( ) const {
      return "rectangulo";
   }

   double perimetro( ) const {
      return 2 * base + 2 * altura;
   }
};

int main( ) {
   circulo c(10);
   cuadrado s(5);
   rectangulo r(3, 4);

   nota: {
      figura& f = c;       // gracias a la herencia, podemos declarar una referencia de tipo figura que esté vinculada tanto a un círculo, como a un cuadrado, como a un rectángulo
      figura* p = &s;      // también podemos hacer que un apuntador apunte a cualquiera de esos tres
   }

   figura* arr[3] = { &c, &s, &r };    // tres apuntadores: el [0] apunta a un círculo, el [1] a un cuadrado y el [2] a un rectángulo

   int indice;
   std::cin >> indice;                                   // leemos un índice (0, 1 o 2)

   figura& f = *arr[indice];                             // a partir del índice dado por el usuario, agarramos alguna de las figuras; ¿cuál agarramos? ¡quién sabe! (y tampoco importa)
   std::cout << f.nombre( ) << " " << f.perimetro( );    // gracias al mecanismo virtual, imprimimos el nombre y el perimetro correctos de la figura, haya sido la figura que haya sido
}
