[C con Clase] Ejercicio Racional

Steven Davidson srd4121 en njit.edu
Mar Abr 17 07:36:02 CEST 2012


Hola Luis,

On 4/16/2012 11:16 PM, Luis Gutierrez Gomez wrote:
>

[CORTE]

> Cordiales Saludos:
>

Veamos el código fuente.

>
>
>
> #include<iostream>
>
> using std::cout;
> using std::endl;
>
> class Racional {
> public:
>   Racional( int num = 1, int den = 2 );

Sugiero inicializar un número racional a 0 (cero), por lo que sería,

Racional( int num = 0, int den = 1 );

Supongo que puedes elegir 1, pero al menos establece que el denominador 
es 1, si no se indica explícitamente. De esta manera, podemos 
representar números enteros en racionales y así obtenemos una conversión 
lógica y funcional. Por ejemplo,

Racional p(2);  // = Racional(2,1)

que tiene sentido tanto como 2 que como 2/1.

>   void EstableceRacional( int numera, int denomi);

Esta función miembro no es necesaria, ya que se puede hacer directamente 
con el lenguaje a través del operador de asignación. Por ejemplo,

Racional p, q(1,3);

p = q;
q = Racional(-1,2);

e incluso,

p = 3;  // =>  p = Racional(3)  =>  p = Racional(3,1)


Lo que sí podríamos hacer es establecer un miembro en particular: 
numerador o denominador; por ejemplo,

void AsignaNumerador( int n );
void AsignaDenominador( int d );

>   Racional ObtieneRacional();

Esto no tiene sentido, porque estás realizando una copia de "este 
objeto". Si quieres una copia, usa el operador de asignación del 
lenguaje, como expliqué antes.

Si quieres mantener esta función miembro, entonces al menos indica que 
es constante.

>   Racional SumaRacional( const Racional&der )const;
>      Racional RestaRacional( const Racional&der ) const;
>   Racional MultiplicaRacional( const Racional&der ) const;
>   Racional DivideRacional( const Racional&der ) const;

Como expliqué en el correo-e anterior, no es necesario escribir 
"Racional" para indicar el "tipo" de operación, ya que estas funciones 
son miembros de la clase 'Racional'. Es decir, se sobreentiende que se 
trata de funciones relativas a los racionales.

>   void ImprimeRacional();
>   void ImprimeFlotante();
>

Estas dos funciones miembro deberían ser constantes, ya que no cambian 
el estado de este objeto.

Personalmente, habría creado una sola función para imprimir en forma 
racional, 'imprime()', y otra para convertir a 'double': 'calcular()' p 
'toDouble()'. Con esta segunda función miembro podemos usarla para 
cualquier tarea, tanto si es para imprimir el número calculado como si 
es para realizar otros cálculos.

> private:
>   void ReduceRacional();

Quizá sería mejor que retornase "este objeto" en lugar de no retornar nada.

>   int numerador;
>   int denominador;
> };
>
> Racional::Racional( int num, int den )
> {
>   EstableceRacional( num, den );
>   ReduceRacional();
> }
>
> void Racional::EstableceRacional( int numera, int denomi )
> {
>   numerador = numera;
>   denominador = denomi;

Esto no es del todo correcto. No siempre podemos aceptar cualquier valor 
para asignarlo a nuestros datos miembro. En este caso, el denominador NO 
puede ser 0 (cero), porque no podríamos representar el resultado como un 
número racional.

> }
>
>
>
> Racional Racional::ObtieneRacional()
> {
>   Racional Rdev;
>   Rdev.numerador = numerador;
>   Rdev.denominador = denominador;
>   return Rdev;
> }
>

Como dije antes, esta función no es necesaria.

>
> void Racional::ReduceRacional()
> {
>   int menor;
>
>   menor = numerador<  denominador ? numerador : denominador;
>   while (  menor>  1 ){
>    if ( ( numerador % menor == 0  )&&( denominador % menor == 0 ) ){
>     numerador = numerador/menor;
>     denominador = denominador/menor;

Deberías acostumbrarte a usar el operador /= y otros parecidos.

>    }
>    menor--;
>   }
> }
>
> Racional Racional::SumaRacional( const Racional&der ) const
> {
>   Racional Rr;
>
>   Rr.denominador = denominador * der.denominador;
>   Rr.numerador = ( ( ( Rr.denominador / denominador ) * numerador ) + ( ( Rr.denominador / der.denominador ) * der.numerador ) );

Podríamos instanciar el objeto con toda la información, en lugar de 
realizar varias asignaciones. Esto es,

Racional Racional::SumaRacional( const Racional &der ) const
{
   Racional Rr( Rr.denominador / denominador * numerador + 
Rr.denominador / der.denominador * der.numerador, denominador * 
der.denominador );

   Rr.ReduceRacional();
   return Rr;
}

>   Rr.ReduceRacional();
>   return Rr;
> }
>
> Racional Racional::RestaRacional( const Racional&der ) const
> {
>   Racional Rr;
>
>   Rr.denominador = denominador * der.denominador;
>   Rr.numerador = ( ( ( Rr.denominador / denominador ) * numerador ) - ( ( Rr.denominador / der.denominador ) * der.numerador ) );

Aquí haríamos lo mismo que antes.

>   Rr.ReduceRacional();
>   return Rr;
> }
>
>
>
> Racional Racional::MultiplicaRacional( const Racional&der ) const
> {
>   Racional Rr;
>
>   Rr.numerador = numerador * der.numerador;
>   Rr.denominador = denominador * der.denominador;

Lo mismo que antes.

>   Rr.ReduceRacional();
>   return Rr;
> }
>
> Racional Racional::DivideRacional( const Racional&der ) const
> {
>   Racional Rr;
>
>   Rr.numerador = numerador * der.denominador;
>   Rr.denominador = denominador * der.numerador;

Lo mismo.

>   Rr.ReduceRacional();
>   return Rr;
> }
>
>
> void Racional::ImprimeRacional()
> {
>   cout<<  numerador<<" / "<<  denominador<<  endl;

Como dije en el correo-e anterior, no recomiendo agregar 'endl' en esta 
función, porque no podríamos eliminar su comportamiento si quisiéramos, 
anulando la utilidad de esta función en casos generales.

Si quieres agregar un salto de línea, entonces hazlo en su lugar, cuando 
lo necesites.

> }
>
> void Racional::ImprimeFlotante()
> {
>   cout<<  (float)numerador / (float)denominador<<  endl;
>

Aquí tenemos el mismo problema que en la función anterior.

> }
>
>
>
> int main ()
> {
>   Racional R1, R2( 8, 12), R8( 6, 26);
>   R2.ImprimeRacional();
>   R1 = R2.SumaRacional(R8);
>   R1.ImprimeRacional();
>   R1.ImprimeFlotante();
>   R1 = R2.RestaRacional(R8);
>   R1.ImprimeRacional();
>   R1.ImprimeFlotante();
>   R1 = R2.MultiplicaRacional(R8);
>   R1.ImprimeRacional();
>   R1.ImprimeFlotante();
>   R1 = R2.DivideRacional(R8);
>   R1.ImprimeRacional();
>   R1.ImprimeFlotante();
>   return 0;
> }
>


Espero que todo esto te oriente.

Steven





Más información sobre la lista de distribución Cconclase