Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

Перейдем к изучению менее абстрактных и более реалистичных понятий, поддерживаемых в языке С++.

9.7.1. Типы аргументов

Определяя конструктор класса

Date
в разделе 9.4.3, мы использовали в качестве аргументов три переменные типа
int
. Это породило несколько проблем.

Date d1(4,5,2005); // Ой! Год 4, день 2005

Date d2(2005,4,5); // 5 апреля или 4 мая?

Первая проблема (недопустимый день месяца) легко решается путем проверки в конструкторе. Однако вторую проблему (путаницу между месяцем и днем месяца) невозможно выявить с помощью кода, написанного пользователем. Она возникает из-за того, что существуют разные соглашения о записи дат; например, 4/5 в США означает 5 апреля, а в Англии — 4 мая. Поскольку эту проблему невозможно устранить с помощью вычислений, мы должны придумать что-то еще. Очевидно, следует использовать систему типов.

// простой класс Date (использует тип Month)

class Date {

public:

enum Month {

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

};

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

// ...

private:

int y; // год

Month m;

int d; // день

};

Когда мы используем тип

Month
, компилятор выдаст ошибку, если мы поменяем местами месяц и день. Кроме того, перечисление
Month
позволяет использовать символические имена. Такие имена, как правило, легче читать и записывать, чем работать с числами, подвергаясь риску ошибиться.

Date dx1(1998, 4, 3); // ошибка: 2-й аргумент не имеет

// тип Month

Date dx2(1998, 4, Date::mar); // ошибка: 2-й аргумент не имеет

// тип Month

Date dx2(4, Date::mar, 1998); // Ой: ошибка на этапе выполнения:

// день 1998

Date dx2(Date::mar, 4, 1998); // ошибка: 2-й аргумент не имеет

// тип Month

Date dx3(1998, Date::mar, 30); // OK

Этот код решает много проблем. Обратите внимание на квалификатор

Date
перечисления
mar: Date::mar
. Тем самым мы указываем, что это перечисление
mar
из класса
Date
. Это не эквивалентно обозначению
Date.mar
, поскольку
Date
— это не объект, а тип, а
mar
— не член класса, а символическая константа из перечисления, объявленного в классе. Обозначение
::
используется после имени класса (или пространства имен; см. раздел 8.7), а
.
(точка) — после имени объекта.

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

А нельзя ли подобным образом выявить путаницу между днем месяца и годом? Можно, но решение этой проблемы будет не таким элегантным, как для типа

Month;
помимо всего прочего, возможно, что мы имели в виду именно четвертый год. Даже если мы ограничимся современной эпохой, в перечисление придется включать слишком много лет.

Вероятно, было бы лучше всего (не вникая в предназначение класса Date) написать следующий код:

class Year { // год в диапазоне [min:max)

static const int min = 1800;

static const int max = 2200;

public:

class Invalid { };

Year(int x) : y(x) { if (x<min || max<=x) throw Invalid; }

int year { return y; }

private:

int y;

};

class Date {

public:

enum Month {

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

};

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

// ...

private:

Year y;

Month m;

int d; // день

  • Читать дальше
  • 1
  • ...
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: