Que el programa te arroje los resultados esperados en todos los apartados menos en ese no implica necesariamente que el programa esté bien:
Has de saber que el destructor de
std::vector<T> no es virtual. Esto quiere decir que si usas polimorfismo te puedes encontrar con la desagradable sorpresa de que no se invoca al destructor de
Poli, con lo que toda la memoria reservada por este objeto o por sus variables internas se quedará en el limbo.
Código C++:
Ver originalclass NoVirtualA
{
public:
NoVirtualA(){}
~NoVirtualA()
{ std::cout << "NoVirtualA::~NoVirtualA()" << std::endl; }
};
class NoVirtualB : public NoVirtualA
{
public:
NoVirtualB(){}
~NoVirtualB()
{ std::cout << "NoVirtualB::~NoVirtualB()" << std::endl; }
};
class VirtualA
{
public:
VirtualA(){}
virtual ~VirtualA()
{ std::cout << "VirtualA::~VirtualA()" << std::endl; }
};
class VirtualB : public VirtualA
{
public:
VirtualB(){}
~VirtualB()
{ std::cout << "VirtualB::~VirtualB()" << std::endl; }
};
int main()
{
std::cout << "Caso 1: Se llama a los dos destructores:" << std::endl;
NoVirtualB* noVirtualB = new NoVirtualB;
delete noVirtualB;
std::cout << "Caso 2: Dónde quedó el segundo destructor?" << std::endl;
NoVirtualA* noVirtualA = new NoVirtualB;
delete noVirtualA;
std::cout << "Caso 3: Ahora si aparecen los dos destructores:" << std::endl;
VirtualA* virtualA = new VirtualB;
delete virtualA;
}
Lo suyo, más que herencia, sería tirar de composición, es decir, hacer que el vector fuese un miembro de Poli. Claro está te obligaría a implementar métodos para añadir, eliminar, acceder y modificar los diferentes monomios pero el diseño no sería problemático.
Otro error que tienes es la comparación de datos de tipo double:
Código C++:
Ver originalint Poli::Gr() const
{
int gr= 0;
for (int k=0; k < (*this).size(); k++)
if ( (*this)[k] != 0.0 )
gr= k;
return gr;
}
Si te han explicado las cosas por orden, habrás tenido que ver cómo se almacenan los números decimales en la memoria del ordenador (eso de la mantisa, el exponente, ...). Así mismo habrás visto que un número decimal no tiene por qué tener una representación exacta en binario. Hay números muy tontos como, por ejemplo, 0,3 que en binario tendrá infinitos dígitos: 0.01010101... queda claro entonces que por mucho que te esfuerces no vas a poder almacenar exactamente 0,3 en 32 bits (o 64 o los que te de la gana).
La forma correcta de comparar decimales es asumir que dos números son iguales si se parecen lo suficiente... esto es |A - B| < ALGO. Normalmente
ALGO puedes sustituirlo por 1e-4 o 1e-6... si usas double puedes aumentar la precisión pero normalmente no te va a aportar gran cosa. Por cierto, nota que me estoy quedando con el valor absoluto de la resta.
Más cosillas:
Código C++:
Ver originalint Poli::Gr() const
{
int gr= 0;
for (int k=0; k < (*this).size(); k++)
if ( (*this)[k] != 0.0 )
gr= k;
return gr;
}
Si en el vector almacenas en la posición 0 el monomio menos representativo y de ahí en orden hacia arriba... por qué fuerzas al código a recorrer todo el polinomio desde el principio si lo único que te interesa es el último valor?? Funcionar funciona, pero la forma de hacerlo no es desde luego la más adecuada. Lo suyo sería empezar desde el final y quedarse con el primer valor distinto de 0... después de eso salir del bucle porque no tiene sentido seguir comprobando valores.
Seguimos:
Código C++:
Ver originalPoli Residuo(Poli p, Poli q)
{
Poli a, b, c, r, t;
Poli s;
s.push_back(0);
double f[q.Gr()-p.Gr()];
for(int i=0; i<=q.Gr()-p.Gr(); i++)
f[i]=0;
f[q.Gr()-p.Gr()]=q[q.Gr()]/p[p.Gr()];
for(int j=0; j<=q.Gr()-p.Gr(); j++)
a.push_back(f[j]);
b=Mult(p, a);
s = Suma(s, a);
c=Resta(q, b);
return c;
}
En la función anterior centrémonos en la línea:
¿Qué sucede si p.Gr() es mayor que q.Gr()? Se puede crear un array con tamaño negativo? la respuesta rápida es que no. ¿Es muy importante esto? pse... si miramos otra función:
Código C++:
Ver originalPoli MCD(Poli p, Poli q)
{
Poli m;
do
{
m= Residuo(p, q); // <<<--- AQUI!!!
q = p;
p = m;
}
while(m.Gr() != 0);
return m;
}
Pues lo mismo empieza a tener sentido el error que comentas :)
Y ya como bonus un pequeño detalle. Pasar a una función objetos por valor implica hacer una copia de los mismos. Para lo que estás haciendo ahora mismo no es significativo, pero es una mala práctica porque reduce muchísimo el rendimiento. Lo más común es pasar los objetos como referencias constantes, lo que evita crear una copia en cada llamada:
Código C++:
Ver originalPoli MCD(const Poli& p, const Poli& q)
Lo bueno de aplicar esta solución es que no tienes que modificar para nada el código de la función!!!
Un saludo.