Чтение онлайн

на главную - закладки

Жанры

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

{

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

}

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

{

if (m<1 || 12<m) return false;

// ...

}

Имея это определение класса

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

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

Обратите внимание на то, что
Month
— это отдельный тип. Он может быть неявно преобразован в тип
int
, но неявного преобразования типа
Month
в тип
int
не существует. Это имеет смысл, поскольку каждый объект класса
Month
имеет эквивалентное целое значение, но большинство целых чисел не имеет эквивалентного значения типа
Month
. Например, мы преднамеренно написали неправильную инициализацию.

Month bad = 9999; // ошибка: целое число невозможно преобразовать

//
объект типа Month

Если вы настаиваете на использовании обозначения
Month(9999)
, то сами будете виноваты! Во многих ситуациях язык С++ не пытается останавливать программиста от потенциально опасных действий, если программист явно на этом настаивает; в конце концов, программисту, действительно, виднее.

К сожалению, мы не можем определить конструктор для перечисления, чтобы проверить начальные значения, но написать простую функцию для проверки не составляет труда.

Month int_to_month(int x)

{

if (x<jan || dec<x) error("неправильный месяц");

return Month(x);

}

Теперь можно написать следующий код:

void f(int m)

{

Month mm = int_to_month(m);

// ...

}

Для чего нужны перечисления? В основном перечисление полезно, когда нам нужно множество связанных друг с другом именованных целочисленных констант. Как правило, с помощью перечислений представляют наборы альтернатив (

up
,
down
;
yes
,
no
,
maybe
;
on
,
off
;
n
,
ne
,
e
,
se
,
s
,
sw
,
w
,
nw
) или отличительных признаков (
red
,
blue
,
green
,
yellow
,
maroon
,
crimson
,
black
).

Обратите внимание на то, что элементы перечисления не входят в отдельную область видимости своего перечисления; они находятся в той же самой области видимости, что и имя их перечисления. Рассмотрим пример.

enum Traffic_sign { red, yellow, green };

int var = red; // примечание: правильно Traffic_sign::red

Этот код вызывает проблемы. Представьте себе, что в вашей программе в качестве глобальных используются такие распространенные имена, как

red
,
on
,
ne
и
dec
. Например, что значит
ne:
“северо-восток” (northeast) или “не равно” (nor equal)? Что значит
dec:
“десятичный” (decimal) или “декабрь” (December)? Именно о таким проблемах мы предупреждали в разделе 3.7. Они легко возникнут, если определить перечисление с короткими и общепринятыми именами элементов в глобальном пространстве имен. Фактически мы сразу сталкиваемся с этой проблемой, когда пытаемся использовать перечисление
Month
вместе с потоками
iostream
, поскольку для десятичных чисел существует манипулятор с именем
dec
(см. раздел 11.2.1). Для того чтобы избежать возникновения этих проблем, мы часто предпочитаем определять перечисления в более ограниченных областях видимости, например в классе. Это также позволяет нам явно указать, на что ссылаются значения элементов перечисления, такие как
Month::jan
и
Color::red
. Приемы работы с перечислениями описываются в разделе 9.7.1. Если нам очень нужны глобальные имена, то необходимо минимизировать вероятность коллизий, используя более длинные или необычные имена, а также прописные буквы. Тем не менее мы считаем более разумным использовать имена перечислений в локальных областях видимости.

9.6. Перегрузка операторов

Для класса или перечисления можно определить практически все операторы, существующие в языке С++. Этот процесс называют перегрузкой операторов (operator overloading). Он применяется, когда требуется сохранить привычные обозначения для разрабатываемого нами типа. Рассмотрим пример.

enum Month {

Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec

};

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

Возвращение Безумного Бога 5

Тесленок Кирилл Геннадьевич
5. Возвращение Безумного Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Возвращение Безумного Бога 5

Холодный ветер перемен

Иванов Дмитрий
7. Девяностые
Фантастика:
попаданцы
альтернативная история
6.80
рейтинг книги
Холодный ветер перемен

Кровь, золото и помидоры

Распопов Дмитрий Викторович
4. Венецианский купец
Фантастика:
альтернативная история
5.40
рейтинг книги
Кровь, золото и помидоры

Наследник павшего дома. Том I

Вайс Александр
1. Расколотый мир
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Наследник павшего дома. Том I

Книга 5. Империя на марше

Тамбовский Сергей
5. Империя у края
Фантастика:
альтернативная история
5.00
рейтинг книги
Книга 5. Империя на марше

Генерал Скала и сиротка

Суббота Светлана
1. Генерал Скала и Лидия
Любовные романы:
любовно-фантастические романы
6.40
рейтинг книги
Генерал Скала и сиротка

Мимик нового Мира 14

Северный Лис
13. Мимик!
Фантастика:
юмористическое фэнтези
постапокалипсис
рпг
5.00
рейтинг книги
Мимик нового Мира 14

Стрелок

Астахов Евгений Евгеньевич
5. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Стрелок

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Сержант. Назад в СССР. Книга 4

Гаусс Максим
4. Второй шанс
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Сержант. Назад в СССР. Книга 4

Третий. Том 2

INDIGO
2. Отпуск
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий. Том 2

Боксер 2: назад в СССР

Гуров Валерий Александрович
2. Боксер
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Боксер 2: назад в СССР

Вопреки судьбе, или В другой мир за счастьем

Цвик Катерина Александровна
Любовные романы:
любовно-фантастические романы
6.46
рейтинг книги
Вопреки судьбе, или В другой мир за счастьем

Кротовский, сколько можно?

Парсиев Дмитрий
5. РОС: Изнанка Империи
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Кротовский, сколько можно?