0

estoy empezando a programar y he realizado mi primer programa, el programa en si funciona, pero veo que para los pocos pasos que hay que dar se escribe mucho código, se que hay código innecesario, creo que hay otra forma mas bonita de hacerlo (o un código mas bonito), y lo que busco es aprender a escribir buen código, no solo que funcione, aprender a base de errores y correcciones, así que espero que alguien me corrija el programa y me enseñe, gracias de antemano.

#include <iostream>

int main() 
{

     // calculamos Entrada
    float hora_entrada;
    float minuto_entrada;
    std::cout << "Introduce hora de entrada: \n";
    std::cin >> hora_entrada;
    std::cout << ":";
    std::cin >> minuto_entrada;
    std::cout << "\n";
    float hora_entrada2;
    hora_entrada2 = hora_entrada * 60;
    float entrada = (hora_entrada2 + minuto_entrada);
    std::cout << entrada << "minutos";
    std::cout << "\n";

    // Calculamos Salida
    float hora_salida;
    float minuto_salida;
    std::cout << "Introduce hora de salida: \n";
    std::cin >> hora_salida;
    std::cout << ":";
    std::cin >> minuto_salida;
    std::cout << "\n";
    float hora_salida2;
    hora_salida2 = hora_salida * 60;
    float salida = (hora_salida2 + minuto_salida);
    std::cout << salida << "minutos";
    std::cout << "\n";

    // Calculamos el tiempo total
    float jornada_diaria_minutos;
    jornada_diaria_minutos = (salida - entrada);
    float jornada_diaria_horas;
    jornada_diaria_horas = (jornada_diaria_minutos / 60);
    std::cout << "Su jornada de trabajo es de: " << jornada_diaria_minutos << " minutos ";
    std::cout << "que serian " << jornada_diaria_horas << " horas \n";

    return 0;
}
Trauma
  • 25,297
  • 4
  • 37
  • 60
Kiko
  • 1
  • 1
  • 1
    Pero ¿Qué es lo que quieres que haga tu código y qué hace ahora miso? – PaperBirdMaster Jan 24 '19 at 18:58
  • El primer paso es refactorizar porciones de código que sean similares en funciones y/o procedimientos de tal modo que la función `main` sea lo más concisa posible. – Xam Jan 24 '19 at 19:59
  • aparte de que se pasen a métodos las secciones que abarcan de un comentario a otro ¿Qué más ocupas en la respuesta? – Ruslan López Jan 25 '19 at 18:45

2 Answers2

2

Estructuras de datos

El programa tiene que leer dos horas diferentes. Ya tienes dos elmentos del mismo tipo... es un buen momento para crear una estructura de datos:

struct Time
{
  int hours;
  int mins;
};

¿Y por qué una estructura de datos y no algo que nos devuelva directamente los minutos totales?

Por varias razones:

  • Los datos son más fáciles de tratar si están debidamente organizados (es decir, estructurados)
  • C++ es orientado a objetos, vamos a aprovechar ese punto.
  • Es mi respuesta y la estoy escribiendo yo :)

Bien, seguimos.

Sobrecarga de operadores

Además, las dos horas se leen desde el teclado. Así que no estaría de más proporcionar un mecanismo que almacene una hora en esta estructura. Esto no pretende ser una clase magistral porque entonces sería demasiado larga, así que asumiremos que el usuario va a introducir los valores correctos. Partiendo de esta base podemos sobrecargar fácilmente el operador de extracción de la siguiente manera:

std::istream & operator>>(std::istream& is, Time & time)
{
    char sep;
    is >> time.hours >> sep >> time.mins;
    return is;
}

Lo que hace esta función es leer un entero (la hora), después lee un carácter (el separador), el cual descarta, y finalmente un segundo entero (los minutos). Y sí, esa cosa tan rara es una función, puedes comprobarlo fácilmente con el siguiente código:

Time time;
operator>>(std::cin, time);
std::cout << time.hours << ':' << time.mins;

Si introduces por teclado una hora (horas:minutos) te la imprimirá por pantalla... aunque claro, los operadores no están pensados para ser usados como funciones. Seguramente este otro ejemplo te parecerá más bonito pese a que a nivel funcional son exactamente iguales:

Time time;
std::cin >> time;
std::cout << time.hours << ':' << time.mins;

El caso es que con lo que hemos visto hasta ahora el inicio del programa ya queda mucho más legible:

Time entrada, salida;
std::cout << "Introduce hora de entrada: \n";
std::cin >> entrada;
std::cout << "Introduce hora de salida: \n";
std::cin >> salida;

Conversión de valores

A continuación vemos que se pide convertir la hora a minutos totales... es decir, otra función. En este caso vamos a aventurarnos a crear una función miembro... por tener variedad:

struct Time
{
  int hours;
  int mins;

  int ToMinutes() const
  { return hours * 60 + mins; }
};

Con esto el inicio del programa ya estaría completo:

Time entrada, salida;
std::cout << "Introduce hora de entrada: \n";
std::cin >> entrada;
std::cout << entrada.ToMinutes() << " minutos\n";
std::cout << "Introduce hora de salida: \n";
std::cin >> salida;
std::cout << salida.ToMinutes() << " minutos\n";

Claro está que esto es C++ y aquí no hay una única forma de resolver los problemas sino cien millones... Otra posibilidad pasaría por aprovechar los operadores de conversión... a mi esta opción no me suele gustar porque es relativamente sencillo meter la pata al programar:

struct Time
{
  int hours;
  int mins;

  operator int() const
  { return hours * 60 + mins; }
};

Con este operador podríamos escribir la siguiente obra gráfica, aberración, engendro, ... cada uno que use el adjetivo que mejor le parezca:

    int opcion1 = entrada;
    int opcion2 = (int)entrada;
    int opcion3 = static_cast<int>(entrada);
    std::cout << opcion1 << ' ' << opcion2 << ' ' << opcion3;

El caso es que, como podrás comprobar si pruebas el ejemplo anterior, funciona. Como digo a mi estos operadores no suelen gustarme demasiado, pero existen y es conveniente conocer al menos su existencia.

Operaciones aritméticas

A continuación se hace una operación de resta de las fechas... en este punto podríamos tomar varios caminos, yo destaco dos:

  • Aprovechar el método ToMinutes. Si ya tenemos el total de minutos, el siguiente paso podría ser, simplemente, restar ambos totales. Esta sería quizás la opción más recomendable en este caso:

    int mins_entrada = entrada.ToMinutes();
    int mins_salida = salida.ToMinutes();
    int total_mins = mins_salida - mins_entrada;
    
  • Crear una función que reste objetos de tipo Time. Esta opción podría ser más versátil en otros contextos... para este caso concreto sirve más como fines didácticos:

    Time operator-(Time const& t1, Time const& t2)
    {
        Time to_return{t1.hours - t2.hours, t1.mins - t2.mins};
        if( to_return.mins < 0 )
        {
            to_return.mins += 60;
            to_return.hours--;
        }
    
        return to_return;
    }
    
    Time diff = salida - entrada;
    int total_mins = diff.ToMinutes();
    

El caso es que ya tenemos el número de minutos entre las dos horas. El único punto que podría ser conflictivo en este punto es sacar las horas con decimales... pero la verdad es que tampoco tiene demasiada complicación: Basta con recordar que si dividimos un entero entre un float el resultado de la operación será un float, es decir, tendrá decimales:

float total_hours = total_mins / 60.f;

Posibles mejoras

Existe una estructura std::tm que sirve para la gestión de fechas y horas. Normalmente no sale a cuenta reinventar la rueda, así que sería conveniente aprender a lidiar con funciones y clases ya existentes. Queda a elección del lector realizar los cambios oportunos para que el programa utilice std::tm en vez de la clase Time.

Conclusiones

Y ya está, ya tenemos el programa terminado, solo falta imprimir los resultados finales.

Puedes ver el código funcionando en wandbox.

eferion
  • 49,291
  • 5
  • 30
  • 72
0
    #include <iostream>
    using namespace std;
//llama a todo el namespace, para facilitar la llamada al los flujos

/*
Debe establecerse la entrada si es Am o PM al igual con la salida o usar el formato 
24Hrs para poder hacer un calculo correcto
*/
int capturaHoras(string msj){ 
//aquí se pedirán los datos de entrada y salida
int hora;
int minutos;

cout<<"Ingrese la hora de " + msj + ", (hora y minutos separados por un espacio):  ";
cin>>hora>>minutos;
cout<<endl<<endl;
return ( (hora*60) + minutos);

}

void calcularJornada(int entrada, int salida){
//aquí se harán los calculos y se mostrarán
cout<<"Los minutos laborados son: "<< (salida-entrada)<<endl<<endl;
cout<<"Convertido a horas es: "<<((salida-entrada)/60)<<endl<<endl;


}

int main(){

cout<<"\tCalcular jornada laboral, en formato 24hrs"<<endl<<endl;

int horaEntrada = capturaHoras("entrada");
int horaSalida = capturaHoras("salida");
//en este punto ya tienes registrada la hora de entrada y salida convertidas en 
minutos

calcularJornada(horaEntrada,horaSalida);    


return 0;
}

Optimicé un poco más, lo que hace tú programa, con uso de métodos simplificas mucho cualquier programa, (al reordenamiento de tu código, se le llama refactorización).

Y si quieres simplificar la llamada a flujos del IO, agrega el namespace en la cabecera. Eso para no escribir su nombre completo std::cout<< (...) ;

También probé tú código, da el calculo mal, tienes que tener en cuenta en que formato vas a calcular o te dará una suma contraria, en este ejemplo usé formato de 24hrs y funciona correctamente.

Puedes modificarlo para que solo acepte valor de 0 a 24 para la hora y 0 a 60 para los minutos.

O, totalmente puedes hacer que sea de 0 a 12 horas, pero tendrías que poner algun check (bool) para saber si será AM o PM, y realizar una operación correcta.

introducir la descripción de la imagen aquí

Igual te anexo una captura, para verlo más claramente

  • Genial, gracias, pero a ver, he leido por ahi que el uso del namespace tiende a dar errores de compilación, por lo que he decidido utilizar std:: , el tema de refactorizar todavia no lo he tocado y por ahora, IO y funciones basicas. – Kiko Jan 24 '19 at 21:06
  • 1
    @Kiko no se a qué te refieres con esos supuestos errores de compilación de los `namespace`... si los usas mal tendrás los mismos problemas que si programas de cualquier manera. Solo son una manera de clasificar la funcionalidad. – eferion Jan 24 '19 at 22:33
  • Aqui, lo leí https://es.stackoverflow.com/questions/460/por-qué-el-usar-using-namespace-std-se-considera-mala-práctica de todas maneras para algo tan simple si lo puedo usar, pero es como todo, si te acostumbras a ponerte el cinturón luego te cuesta hasta el no ponertelo y te sientes incomodo con el, pues igual aqui, si te acostumbras a escribir bien el codigo, luego no te sale ni escribirlo mal, investigare y estudiare estos dias los comentarios que me habeis puesto, muchísimas gracias y sigo aceptando comentarios – Kiko Jan 25 '19 at 09:33