#include <iostream>
using namespace std;

class CTermino  // clase base
{
  private:
    double coeficiente;
  public:
    // Constructor
    CTermino(double k = 1) : coeficiente(k) {}
    double coef() { return coeficiente; }
    virtual void mostrar() = 0;
};

class CTerminoEnX : public virtual CTermino
{
  private:
    int exponenteDeX;
  public:
    // Constructor
    CTerminoEnX(double k = 1, int e = 0) : 
    CTermino(k), exponenteDeX(e) {}
    int expX() { return exponenteDeX; }
    void mostrar() { cout << coef() << "x^" << exponenteDeX; }
};

class CTerminoEnY : public virtual CTermino
{
  private:
    int exponenteDeY;
  public:
    // Constructor
    CTerminoEnY(double k = 1, int e = 0) : 
    CTermino(k), exponenteDeY(e) {}
    int expY() { return exponenteDeY; }
};

class CTerminoEnXY : public CTerminoEnX, public CTerminoEnY
{
  public:
    // Constructor
    CTerminoEnXY(double k = 1, int ex = 0, int ey = 0) : 
    CTermino(k), CTerminoEnX(k, ex), CTerminoEnY(k, ey) {}
    void mostrar() { cout << coef() << "x^" << expX()
                          << "y^" << expY(); }
};

ostream& operator<<(ostream& os, CTermino* t)
{
  t->mostrar();
  return os;
}

void f(CTerminoEnXY* p)
{
  // Clase base normal
  CTerminoEnX *pTx = p; // D a B
  CTerminoEnXY *pTxy = static_cast<CTerminoEnXY *>(pTx); // B a D
  pTxy = dynamic_cast<CTerminoEnXY *>(pTx); // B a D
  
  // Clases hermanas
  CTerminoEnY *pTy = dynamic_cast<CTerminoEnY *>(pTx); // h a H
  //pTy = static_cast<CTerminoEnY *>(pTx); // H a H. Error
  cout << pTy << endl;
  
  // Clase base virtual
  CTermino *pT = p;
  //pTxy = static_cast<CTerminoEnXY *>(pT); // Bv a D. Error.
  pTxy = dynamic_cast<CTerminoEnXY *>(pT); // Bv a D.
  cout << pTxy << endl;
  pTx = dynamic_cast<CTerminoEnXY *>(pT); // Bv a D.
  cout << pTx << endl;
}

int main()
{
  CTerminoEnX *pCTerminoEnX = new CTerminoEnX(3, 2);
  cout << pCTerminoEnX << endl;
  CTerminoEnXY *pCTerminoEnXY = new CTerminoEnXY(2, 5, 3);
  cout << pCTerminoEnXY << endl;
  f(pCTerminoEnXY);
  delete pCTerminoEnX;
  delete pCTerminoEnXY;
  cout << endl;
}

