Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:
Рассмотрим несколько примеров вспомогательных функций (helper functions).
Date next_Sunday(const Date& d)
{
// имеет доступ к объекту d, используя d.day, d.month
// и d.year
// создает и возвращает новый объект класса Date
}
Date next_weekday(const Date& d) { /* ... */ }
bool leapyear(int y) { /* ... */ }
bool operator==(const Date& a, const Date& b)
{
return a.year==b.year
&& a.month==b.month
&& a.day==b.day;
}
bool operator!=(const Date& a, const Date& b)
{
return !(a==b);
}
leapyear
. Часто для идентификации вспомогательных функций используются пространства имен (см. раздел 8.7).
namespace Chrono {
class Date { /* ... */ };
bool is_date(int y, Date::Month m, int d); // true для
// корректных данных
Date next_Sunday(const Date& d) { /* ... */ }
Date next_weekday(const Date& d) { /* ... */ }
bool leapyear(int y) { /* ... */ } // см. пример 10
bool operator==(const Date& a, const Date& b) { /* ... */ }
// ...
}
Обратите внимание на функции
==
и !=
. Это типичные вспомогательные функции. Для многих классов функции ==
и !=
имеют очевидный смысл, но, поскольку это не распространяется на все классы, компилятор не может создать их вместо программиста, как копирующий конструктор или копирующее присваивание. Отметьте также, что мы ввели вспомогательную функцию
is_date
, которая заменяет функцию Date::check
, поскольку проверка корректности даты во многом не зависит от представления класса Date
. Например, нам не нужно знать, как представлены объекты класса Date
для того, чтобы узнать, что дата “30 января 2008 года” является корректной, а “30 февраля 2008 года” — нет. Возможно, существуют аспекты даты, которые зависят от ее представления (например, корректна ли дата “30 января 1066 года”), но (при необходимости) конструктор Date
может позаботиться и об этом. 9.8. Класс Date
Итак, соединим все идеи и понятия вместе и посмотрим, как будет выглядеть класс
Date
. Там, где тело функции содержит лишь комментарий ...
, фактическая реализация слишком сложна (пожалуйста, не пытайтесь пока ее написать). Сначала разместим объявления в заголовочном файле Chrono.h
.
// файл Chrono.h
#include "Chrono.h"
namespace Chrono {
class Date {
public:
enum Month {
jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};
class Invalid { }; //
для генерации в виде исключения
Date(int y, Month m, int d); // проверка и инициализация даты
Date; // конструктор по умолчанию
// операции копирования по умолчанию
// в порядке
// немодифицирующие операции:
int day const { return d; }
Month month const { return m; }
int year const { return y; }
// модифицирующие операции:
void add_day(int n);
void add_month(int n);
void add_year(int n);
private:
int y;
Month m;
int d;
};
bool is_date(int y, Date::Month m, int d); // true для корректных дат
bool leapyear(int y); // true, если y — високосный год
bool operator==(const Date& a, const Date& b);
bool operator!=(const Date& a, const Date& b);
ostream& operator<<(ostream& os, const Date& d);
istream& operator>>(istream& is, Date& dd);
} // Chrono
Определения находятся в файле
Chrono.cpp
.
// Chrono.cpp
namespace Chrono {
// определения функций-членов:
Date::Date(int yy, Month mm, int dd)
:y(yy), m(mm), d(dd)
{
if (!is_date(yy,mm,dd)) throw Invalid;
}
Date& default_date
{
static Date dd(2001,Date::jan,1); // начало XXI века
return dd;
}
Date::Date
:y(default_date.year),
m(default_date.month),
d(default_date.day)
{
}
void Date:: add_day(int n)
{
// ...
}
void Date::add_month(int n)
{
// ...
}
void Date::add_year(int n)
{
if (m==feb && d==29 && !leapyear(y+n)) { // помните о високосных годах!
m = mar; // 1 марта вместо
// 29 февраля
Поделиться с друзьями: