Existen muchas clases de tipo fecha, cada uno con sus particularidades. Nosotros intentaremos desarrollar una clase que se adapte a nuestras necesidades. El diagrama con su correspondiente análisis está aquí. Definiremos nuestra clase CFecha en dos archivos separados (lo más común en proyectos de desarrollo), un archivo CFecha.h que es el archivo de definición de la clase o también llamado archivo de cabecera.
// CFecha.h
/* *************************************
PROGRAMACION ORIENTADA A OBJETOS CON C++
prof. Armando B. VERA
************************************** */
#ifndef CFECHA_H
#define CFECHA_H
#include <iostream>
#include <ostream>
#include <istream>
#include <string>
#include <ctime>
#include <limits>
class CFecha{
private:
int d;
int m;
int a;
std::string mes;
bool mflpd; // true: muestra fecha larga por defecto
bool bisiesto(int a_in);
bool validaFecha(int d_in, int m_in, int a_in);
bool validaAnio(int a_in);
bool validaMes(int m_in);
bool validaDia(int d_in, int m_in, int a_in);
static CFecha fDef; // Fecha por defecto
public:
// Constructor con valores por defecto
CFecha(int d_in=0, int m_in=0, int a_in=0, std::string mes="", bool mflpd=true);
// Método para cambiar la fecha por defecto.
void setFDef(int d_in, int m_in, int a_in, std::string mes_in, bool mflpd_in); // ESTUDIAR
CFecha(const CFecha& f); // constructor de copia
~CFecha(); // Destructor
// Métodos de cambio de comportamiento del flujo ostream
void setFA();
void activaFechaCorta();
void activaFechaLarga();
// Metodos de actualización
bool setDia(int dia_in);
bool setMes(int mes_in);
bool setAnio(int a_in);
// Métodos de lectura
int getDia() const;
int getMes() const;
int getAnio() const;
void fl();
std::string fc();
void mf();
void mfc();
void mfl();
int edad(const CFecha& f_act);
// Sobrecarga de operadores
CFecha& operator=(const CFecha& f);
friend std::ostream& operator<<(std::ostream& flout, const CFecha& f);
friend std::istream& operator>>(std::istream& fin, CFecha& f);
};
#endif // CFECHA_H
El archivo de implementación o archivo de definición de los métodos de la clase es un archivo que tienen el mismo nombre que la clase pero con extensión cpp. En nuestro caso el archivo de implementación se llamará CFecha.cpp
Para no saturar y poder explicar cada una de las partes que conforman el archivo de implementación lo vamos a hacer por separado. Lo indicamos con puntos suspensivos antes y después del código cuando hay código antes y cuando hay código después.
// CFecha.cpp
/* **************************************
PROGRAMACIÓN ORIENTADA A OBJETOS CON C++
prof. Armando B. VERA
************************************** */
#include "CFecha.h"
CFecha CFecha::fDef(1,1,1900);
Lo primero que debemos incluir en el archivo de definición de los métodos de nuestra clase CFecha es el archivo de cabecera CFecha.h. Este archivo contiene la definición de la clase y los prototipos de las funciones o métodos de la clase. El primer método a definir es fDef que establece la fecha por defecto que tendrán los objetos del tipo CFecha que utilicen la fecha por defecto. Hay que recordar que fDef es un atributo u objeto del tipo fecha que puede asignarse directamente saltando la comprobación sobre la validez de la fecha asignada, por eso es importante que sea asignada una fecha correcta. En este caso, la fecha por defecto es "1 de enero de 1900"
bool CFecha::bisiesto(const int a_in){
bool valRet; // valor de retorno
if(a_in>1582) {
if(a_in%4==0 && (a_in%100!=0 || a_in%400==0)){
valRet=false;
} else if {
valRet=true;
}
} else if {
valRet=false;
}
return valRet;
}
El método bisiesto retorna un true o false dependiendo del año pasado como argumento. Si corresponde a un año bisiesto retorna true, de lo contrario retorna un false.
En este caso, bool es el valor de retorno, bisiesto es el nombre de la función y la cadena CFecha::bisiesto es para indicar al compilador que la función pertenece a la clase CFecha. El doble dos puntos :: es el operador de resolución de ámbito. Sirve para utilizar funciones con el mismo nombre pero que correspondan a clases distintas.
bool CFecha::validaAnio(const int a_in){
if(a_in>=1582){
return true;
} else {
return false;
}
}
Esta función toma como parámetro un entero constante a_in si es una año mayor o igual que 1582 retorna true, de lo contrario, retorna false. Se toma ese año como fecha válida porque en ese año se realizó un ajuste del calendario. Al mes de octubre se le suprimieron los días que van del 5 al 14, es decir, el días siguiente al 4 de octubre de 1582 le sucedió el días 15 de octubre. Por lo tanto no tiene sentido que en el sistema se trabaje con tantos errores. En todo caso, serán los historiadores quienes ajustarán los datos cuando los consideren conveniente.
bool CFecha::validaMes(const int m_in){
if(m_in>0 && m_in <=12) {
return true;
} else {
return false;
}
}
Los meses se enumeran comenzando por el mes 1 enero, 2 febrero, etc., siendo 12 el correspondiente a diciembre. La función evalúa si el valor ingresado para el mes es válido.
bool CFecha::validaDia(const int d_in, const int m_in, const int a_in){
int diaMax=0;
switch(m_in){
case 2:
diaMax=28+bisiesto(a_in);
break;
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
diaMax=31;
break;
case 4: case 6: case 9: case 11:
diaMax=30;
break;
// throw errorFecha();
}
if(d_in >0 && d_in <=diaMax){
return true;
} else {
return false;
}
}
Para validar un día cualquiera de un mes determinado es necesario conocer el mes y el año, por eso la función tiene tres parámetros.
Un día es válido si está entre el día 1 y el 28, 29, 30 o 31. Como el limite superior para el rango depende del mes, se considera ese limite superior con una variable diaMax que adoptará distintos valores dependiendo del mes en cuestión. La sentencia switch permite asignar el valor correcto a la variable diaMax dependiendo de los valores que se le pasa por el parámetro m_in a switch. Por ejemplo, si m_in vale 2, (case 2) a diaMax se le asigna el valor 28 + el resultado de las consulta del método bisiesto() que retorna 1 (true) o 0 (false) dependiendo del años en cuestión.
// Representación de cadena
void CFecha::fl(){
switch(m) {
case 1:
mes="Enero";
break;
case 2:
mes="Febrero";
break;
case 3:
mes="Marzo";
break;
case 4:
mes="Abril";
break;
case 5:
mes="Mayo";
break;
case 6:
mes="Junio";
break;
case 7:
mes="Julio";
break;
case 8:
mes="Agosto";
break;
case 9:
mes="Septiembre";
break;
case 10:
mes="Octubre";
break;
case 11:
mes="Noviembre";
break;
case 12:
mes="Diciembre";
break;
// throw errorFecha();
}
if(mflpd==false){
mes=mes.substr(0,3);
}
}
Esta función que más se parece a un procedimiento ya que no retorna un valor (aunque podría hacerlo) tiene por misión asignar una representación en cadena del mes. Para ello utiliza un atributo de tipo string llamado mes. Si la variable de tipo bool mflpd es falso lo que significa que se mostrara el mes en forma abreviada, se extrae una subcadena (las tres primeras letras) y se vuelve a asignar a la variable mes.
// *************************************
void CFecha::activaFechaCorta(){
mflpd=false;
fc();
}
void CFecha::activaFechaLarga(){
mflpd=true;
fl();
}
CFecha::CFecha(int d_in, int m_in, int a_in, std::string mes_in, bool mflpd_in): d(d_in), m(m_in), a(a_in){
if(!(validaAnio(a) && validaMes(m) && validaDia(d,m,a))){
// std::cout << "Fecha no válida. Se asigna la fecha por defecto" << std::endl;
d=fDef.d;
m=fDef.m;
a=fDef.a;
}
mflpd=mflpd_in;
fl();
}
void CFecha::set_fDef(int d_in, int m_in, int a_in, std::string mes_in, bool mflpd_in){
fDef.d=d_in;
fDef.m=m_in;
fDef.a=a_in;
fDef.mes=mes_in;
fDef.mflpd=mflpd_in;
}
CFecha::CFecha(const CFecha& f){
d=f.d;
m=f.m;
a=f.a;
mes=f.mes;
}
CFecha::~CFecha(){};
.... Material aún sin revisar.