Программа 46. модификация дат
В данной программе написаны функции для модификации даты, которые возвращают ссылку на измененную дату.
// Файл DateCl_6.cpp
class Date{
int d, m, y; // День, месяц и год
public:
Date(int = 0, int = 0, int = 0); // Конструктор
Date& Add_Year(int n); // Добавить к дате n лет
Date& Add_OneDay(); // Добавить к дате 1 день
Date& Add_Day(int n); // Добавить к дате n дней
Date& Add_OneMonth(); // Добавить к дате 1 месяц
Date& Add_Month(int n); // Добавить к дате n месяцев
void Print();
};
#include <iostream.h>
void Date::Print()
{
cout << d << '.' << m <<'.'<< y;
}
// leap: возвращает 1, если год year високосный и 0, если нет
int leap(int year)
{ return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; }
Date& Date::Add_Year(int n)
{
if(m == 2 && d == 29 && leap(y + n) != 1){ m = 3; d = 1; }
y += n;
return *this; // Возвращаем ссылку на измененный объект
}
Здесь внутри функции Add_Year ключевое слово this имеет значение указателя на тот объект класса Date, для которого функция вызвана. Например, далее в main есть инструкция вызова функции Add_Year для объекта Studies:
Studies.Add_Year(4);
Здесь во время работы Add_Year указатель this имеет значение адреса переменной Studies, а выражение *this есть сам объект Studies.
// Массив дней в месяцах для невисокосного и високосного года
char daytab[2][13] ={{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
Date& Date::Add_OneDay()
{
if(d < daytab[leap(y)][m]) // Не последний день месяца
d++;
else if(m < 12){ // Последний день месяца, но не последний года
d = 1; m++;
}
else{ // Последний день года
d = 1; m = 1; y++;
}
return *this;
}
Увеличение даты на n дней реализуется n-кратным вызовом функции увеличения даты на 1 день.
Date& Date::Add_Day(int n) // Добавить к дате n дней
{
for(int i = 0; i < n; i++) // Вызываем n раз функцию
Add_OneDay(); // увеличения даты на 1 день
return *this;
}
Если исходная дата приходится на декабрь, через месяц будет то же число января следующего года. Для 28, 29, 30 или 31 января, считаем, что через 1 месяц будет последнее число февраля. Последнее число следующего месяца будет также, если исходная дата – последнее число месяца, независимо от числа дней в месяцах.
Date& Date::Add_OneMonth() // Добавить к дате 1 месяц
{
if(m == 12){ // Если декабрь,то
m = 1; y++; // будет январь следующего года
}
else if((m == 1 && d > 28) || d == 31){ // Если январь, число > 28 или
// последний день промежуточного месяца,
m++; // наступит последнее число
d = daytab[leap(y)][m]; // следующего месяца
}
else
m++; // Следующий месяца
return *this;
}
Date& Date::Add_Month(int n) // Добавить к дате n месяцев
{
for(int i = 0; i < n; i++) // n раз
Add_OneMonth(); // добавляем по 1 месяцу
return *this;
}
// Реализация конструктора
#include <dos.h>
Date::Date(int dd, int mm, int yy)
{
date sysd; // Системная дата
getdate(&sysd); // Получение системной даты
d = dd ? dd : sysd.da_day;
m = mm ? mm : sysd.da_mon;
y = yy ? yy : sysd.da_year;
}
#include <conio.h>
int main()
{
Date Studies(1, 9, 2005);
cout << "Начало учебы: "; Studies.Print(); cout << endl;
Studies.Add_Year(4);
Studies.Add_Month(9);
Studies.Add_Day(21);
cout << "Конец учебы: "; Studies.Print(); cout << endl;
Date Today; // Использование конструктора по умолчанию, сегодня
cout << "Сегодня: "; Today.Print(); cout << endl;
Today.Add_Year(1).Add_Month(1).Add_Day(1);
cout << "Через 1 год, 1 месяц и 1 день будет ";
Today.Print(); cout << endl;
getch();
return 0;
}
Программа выдает:
Начало учебы: 1.9.2005
Конец учебы: 22.6.2010
Сегодня : 12.4.2006
Через 1 год 1 месяц 1 и один день будет 13.5.2007
Обсудим инструкцию
Today.Add_Year(1).Add_Month(1).Add_Day(1);
Когда есть несколько операторов точка (.), они выполняются слева направо, то есть приведенная инструкция эквивалентна следующей:
((Today.Add_Year(1)).Add_Month(1)).Add_Day(1);
Выражение Today.Add_Year(1) во внутренних скобках равно дате Today, увеличенной на 1 год, так как Add_Year возвращает ссылку на объект, для которого вызывается. Далее для этой измененной Today вызывается Add_Month, которая также возвращает дату Today, увеличенную на 1 месяц, которая затем увеличивается на 1 день функцией Add_Day. Возможность писать подобные цепочки вызовов функций обеспечивается тем, что функции возвращают ссылки на объекты.
Деструкторы
В конструкторах при создании объектов могут захватываться некоторые ресурсы, например, выделяться память, открываться файлы и т. п. При уничтожении объектов ресурсы должны освобождаться. Эту работу выполняют специальные функции-члены класса – деструкторы.
Имя деструктора совпадает с именем класса, только впереди добавляется знак ~ (тильда). Деструктор не имеет аргументов, и так же, как и конструктор, ничего не возвращает.
Деструкторы вызываются неявно, когда автоматическая переменная выходит из зоны видимости, когда оператором delete удаляется объект, созданный в свободной памяти оператором new.