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

  Что делать при обнаружении некорректной даты? В каком месте кода происходит поиск некорректных дат? В разделе 5.6 мы узнали, что в этом случае следует сгенерировать исключение, и самым очевидным местом для этого является место первого создания объекта класса Date. Если мы создали правильные объекты класса Date и все функции-члены написаны правильно, то мы никогда не получим объект класса Date с неверным значением. Итак, следует предотвратить создание неправильных объектов класса Date.


// простой класс Date (предотвращаем неверные даты)

class Date {

public:

  class Invalid { };         // используется как исключение

  Date(int y, int m, int d); // проверка и инициализация даты

  // ...

private:

  int y, m, d;  // год, месяц, день

  bool check; // если дата правильная, возвращает true

};


Мы поместили проверку корректности даты в отдельную функцию check, потому что с логической точки зрения эта проверка отличается от инициализации, а также потому, что нам может потребоваться несколько конструкторов. Легко видеть, что закрытыми могут быть не только данные, но и функции.


Date::Date(int yy, int mm, int dd)

     :y(yy), m(mm), d(dd) // инициализация данных - членов класса 

{

  if (!check) throw Invalid; // проверка корректности

}


bool Date::check // возвращает true, если дата корректна

{

  if (m<1 || 12

  // ...

}


Имея это определение класса Date, можно написать следующий код:


void f(int x, int y)

try {

  Date dxy(2009,x,y);

  cout << dxy << '\n';   // объявление оператора << см. в разделе 9.8

  dxy.add_day(2);

}

catch(Date::Invalid) {

  error("invalid date"); // функция error определена

  // в разделе 5.6.3

}


Теперь мы знаем, что оператор << и функция add_day всегда будут работать с корректными объектами класса Date. До завершения разработки класса Date, описанной в разделе 9.7, опишем некоторые свойства языка, которые потребуются нам для того, чтобы сделать это хорошо: перечисления и перегрузку операторов. 

9.5. Перечисления

  Перечисление enum (enumeration) — это очень простой тип, определенный пользователем, который задает множество значений (элементов перечисления) как символические константы. Рассмотрим пример.


enum Month {

  jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec

};


“Тело” перечисления — это просто список его элементов. Каждому элементу перечисления можно задать конкретное значение, как это сделано выше с элементом jan, или предоставить компилятору подобрать подходящее значение. Если положиться на компилятор, то он присвоит каждому элементу перечисления число, на единицу превышающее значение предыдущего. Таким образом, наше определение перечисления Month присваивает каждому месяцу последовательные значения, начиная с единицы. Это эквивалентно следующему коду:


enum Month {

  jan=1, feb=2, mar=3, apr=4, may=5, jun=6,

  jul=7, aug=8, sep=9, oct=10, nov=11, dec=12

};


Однако это утомительно и открывает много возможностей для ошибок. Фактически мы сделали две опечатки, пока не получили правильный вариант; лучше все же предоставить компилятору делать простую, повторяющуюся, “механическую” работу. Компилятор такие задачи решает лучше, чем люди, и при этом не устает.

Если не инициализировать первый элемент перечисления, то счетчик начнет отсчет с нуля. Рассмотрим такой пример:


enum Day {

  monday, tuesday, wednesday, thursday, friday, saturday, sunday

};


где monday==0 и sunday==6. На практике лучше всего выбирать начальное значение счетчика, равным нулю.

Перечисление Month можно использовать следующим образом:


Month m = feb;

m = 7;     // ошибка: нельзя присвоить целое число перечислению

int n = m; // OK: целочисленной переменной можно присвоить

           // значение Month

Month mm = Month(7); // преобразование типа int в тип Month

                     //(без проверки)


Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже