Читать интересную книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 100 101 102 103 104 105 106 107 108 ... 337
функций десяток, нам будет намного проще работать, чем если их будет пятьдесят.

Пятьдесят функций для класса Date! Возможно, вы думаете, что мы шутим. Вовсе нет: несколько лет назад я делал обзор нескольких коммерческих библиотек для работы с календарем и обнаружил в них множество функций вроде next_Sunday(), next_workday() и т.д. Пятьдесят — это совсем не невероятное число для класса, разработанного для удобства пользователей, а не для удобства его проектирования, реализации и сопровождения.

Отметим также, что если представление изменяется, то переписать достаточно только функции, которые имеют к ней прямой доступ. Это вторая важная практическая причина для минимизации интерфейса. Разрабатывая класс Date, мы могли решить, что дату лучше представлять в виде целого числа дней, прошедших с 1 января 1900 года, а не в виде тройки (год, месяц, день). В этом случае нам придется изменить только функции-члены.

Рассмотрим несколько примеров вспомогательных функций (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 февраля

      d = 1;

    }

    y+=n;

  }

  // вспомогательные функции:

  bool is_date(int y, Date::Month m, int d)

  {

    // допустим, что y — корректный объект

    if (d<=0) return false; // d должна быть положительной

    if

1 ... 100 101 102 103 104 105 106 107 108 ... 337
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп.
Книги, аналогичгные Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Оставить комментарий