В данном случае нет необходимости скрывать данные, на которых основана структура Date
Date;
что с ними можно делать? Все что угодно, в том смысле, что мы можем получить доступ ко всем членам объекта today
(и другим объектам типа Date
), а также читать и записывать их по своему усмотрению. Загвоздка заключается в том, что все это не совсем удобно. Все, что мы хотим делать с объектами типа Date
, можно выразить через чтение и запись их членов. Рассмотрим пример.// установить текущую дату 24 декабря 2005 года
today.y = 2005;
today.m = 24;
today.d = 12;
Этот способ утомителен и уязвим для ошибок. Вы заметили ошибку? Все, что является утомительным, уязвимо для ошибок! Например, ответьте, имеет ли смысл следующий код?
Date x;
x.y = –3;
x.m = 13;
x.d = 32;
Вероятно нет, и никто не стал бы писать такую чушь — или стал? А что вы скажете о таком коде?
Date y;
y.y = 2000;
y.m = 2;
y.d = 29;
Был ли двухтысячный год високосным? Вы уверены?
Итак, нам нужны вспомогательные функции, которые выполняли бы для нас самые общие операции. В этом случае нам не придется повторять один и тот же код, а также находить и исправлять одни и те же ошибки снова и снова. Практически для любого типа самыми общими операциями являются инициализация и присваивание. Для типа Date
Date
. Итак, напишем следующий код:// вспомогательные функции:
void init_day(Date& dd, int y, int m, int d)
{
// проверяет, является ли (y,m,d) правильной датой
// если да, то инициализирует объект dd
}
void add_day(Date& dd, int n)
{
// увеличивает объект dd на n дней
}
Попробуем использовать объект типа Date
void f
{
Date today;
init_day(today, 12, 24, 2005); // Ой! (в 12-м году не было
// 2005-го дня)
add_day(today,1);
}
9.4.2. Функции-члены и конструкторы
Мы предусмотрели функцию инициализации для типа Date
Date
оператор вывода <<
(раздел 9.8):void f
{
Date today;
// ...
cout << today << '\n'; // использовать объект today
// ...
init_day(today,2008,3,30);
// ...
Date tomorrow;
tomorrow.y = today.y;
tomorrow.m = today.m;
tomorrow.d = today.d+1; // добавляем единицу к объекту today
cout << tomorrow << '\n'; // используем объект tomorrow
}
Здесь мы “забыли” немедленно инициализировать объект today
init_day
этот объект будет иметь неопределенное значение. Кроме того, “кто-то” решил, что вызывать функцию add_day
лишняя потеря времени (или просто не знал о ее существовании), и создал объект tomorrow
вручную. Это плохой и даже очень плохой код. Вероятно, в большинстве случае эта программа будет работать, но даже самые небольшие изменения приведут к серьезным ошибкам. Например, отсутствие инициализации объекта типа Date
приведет к выводу на экран так называемого “мусора”, а прибавление единицы к члену d
вообще представляет собой мину с часовым механизмом: когда объект today
окажется последним днем месяца, его увеличение на единицу приведет к появлению неправильной даты. Хуже всего в этом очень плохом коде то, что он не выглядит плохим.