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

на главную

Жанры

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

{year 1991 { month jun }}

{ year 1992 { month jan ( 1 0 61.5) } {month feb (1 1 64) (2 2
65.2)}}

{year 2000

{ month feb (1 1 68 ) (2 3 66.66 ) ( 1 0 67.2)}

{month dec (15 15 –9.2 ) (15 14 –8.8) (14 0 –2) }

Этот формат довольно своеобразен. Форматы записи файлов часто оказываются довольно специфическими. В промышленности наблюдается тенденция к широкому использованию все более упорядоченных и иерархически структурированных файлов (например, HTML и XML),
но в действительности мы по-прежнему редко можем контролировать формат файла, который необходимо прочитать. Файлы таковы, каковы они есть, и нам нужно их прочитать. Если формат слишком неудачен или файлы содержат много ошибок, можем написать программу преобразования формата в более подходящий. С другой стороны, мы, как правило, имеем возможность выбирать представление данных в памяти в удобном для себя виде, а при выборе формата вывода часто руководствуемся лишь собственными потребностями и вкусом.

Предположим, данные о температуре записаны в указанном выше формате и нам нужно их прочитать. К счастью, формат содержит автоматически идентифицируемые компоненты, такие как годы и месяцы (немного напоминает форматы HTML и XML). С другой стороны, формат отдельной записи довольно неудобен. Например, в ней нет информации, которая могла бы нам помочь, если бы кто-то перепутал день месяца с часом или представил температуру по шкале Цельсия, хотя нужно было по шкале Фаренгейта, и наоборот. Все эти проблемы нужно как-то решать.

10.11.1. Представление в памяти

Как представить эти данные в памяти? На первый взгляд, необходимо создать три класса,

Year
,
Month
и
Reading
, точно соответствующие входной информации. Классы
Year
и
Month
очевидным образом могли бы оказаться полезными при обработке данных; мы хотим сравнивать температуры разных лет, вычислять среднемесячные температуры, сравнивать разные месяцы одного года, одинаковые месяцы разных лет, показания температуры с записями о солнечном излучении и влажности и т.д. В принципе классы
Year
и
Month
точно отображают наши представления о температуре и погоде: класс
Month
содержит ежемесячную информацию, а класс
Year
— ежегодную. А как насчет класса
Reading
? Это понятие низкого уровня, связанное с частью аппаратного обеспечения (сенсором). Данные в классе
Reading
(день месяца, час и температура) являются случайными и имеют смысл только в рамках класса
Month
. Кроме того, они не структурированы: никто не обещал, что данные будут записаны по дням или по часам. В общем, для того чтобы сделать с данными что-то полезное, сначала их необходимо упорядочить. Для представления данных о температуре в памяти сделаем следующие предположения.

• Если есть показания для какого-то месяца, то их обычно бывает много.

• Если есть показания для какого-то дня, то их обычно бывает много.

В этом случае целесообразно представить класс

Year
как вектор, состоящий из 12 объектов класса
Month
, класс
Month
— как вектор, состоящий из 30 объектов класса
Day
, а класс
Day
— как 24 показания температуры (по одному в час). Это позволяет просто и легко манипулировать данными при решении самых разных задач. Итак, классы
Day
,
Month
и
Year
— это простые структуры данных, каждая из которых имеет конструктор. Поскольку мы планируем создавать объекты классов
Month
и
Day
как часть объектов класса Year еще до того, как узнаем, какие показания температуры у нас есть, то должны сформулировать, что означает “пропущены данные” для часа дня, до считывания которых еще не подошла очередь.

const int not_a_reading = –7777; // ниже абсолютного нуля

Аналогично, мы заметили, что часто в течение некоторых месяцев не производилось ни одного измерения, поэтому ввели понятие “пропущен

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

const int not_a_month = –1;

Три основных класса принимают следующий вид:

struct Day {

vector<double> hour;

Day; // инициализируем массив hour значениями "нет данных"

};

Day::Day

: hour(24)

{

for (int i = 0; i<hour.size; ++i) hour[i]=not_a_reading;

}

struct Month { // месяц

int month; // [0:11] январю соответствует 0

vector<Day> day; // [1:31] один вектор для всех данных по дням

Month // не больше 31 дня в месяце (day[0]

// не используется)

:month(not_a_month), day(32) { }

};

struct Year { // год состоит из месяцев

int year; // положительный == н.э.

vector<Month> month; // [0:11] январю соответствует 0

Year :month(12) { } // 12 месяцев в году

};

В принципе каждый класс — это просто вектор, а классы

Month
и
Year
содержат идентифицирующие члены
month
и
year
соответственно.

В этом примере существует несколько “волшебных констант” (например,
24
,
32
и
12
). Как правило, мы пытаемся избегать таких литеральных констант в коде. Эти константы носят фундаментальный характер (количество месяцев в году изменяется редко) и в остальной части кода не используются. Однако мы оставили их в коде в основном для того, чтобы напомнить вам о проблеме “волшебных чисел”, хотя намного предпочтительнее использовать символьные константы (см. раздел 7.6.1). Использование числа
32
для обозначения количества дней в месяце определенно требует объяснений; в таком случае число
32
действительно становится “волшебным”.

10.11.2. Считывание структурированных значений

Класс

Reading
будет использован только для ввода данных, к тому же он намного проще остальных

struct Reading {

int day;

int hour;

double temperature;

};

istream& operator>>(istream& is, Reading& r)

// считываем показания температуры из потока is в объект r

// формат: (3 4 9.7)

// проверяем формат, но не корректность данных

{

char ch1;

if (is>>ch1 && ch1!='('){ // можно это превратить в объект типа

// Reading?

is.unget;

is.clear(ios_base::failbit);

return is;

}

char ch2;

int d;

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

Ученичество. Книга 1

Понарошку Евгений
1. Государственный маг
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Ученичество. Книга 1

Идеальный мир для Лекаря 7

Сапфир Олег
7. Лекарь
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 7

Обыкновенные ведьмы средней полосы

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Обыкновенные ведьмы средней полосы

Треск штанов

Ланцов Михаил Алексеевич
6. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Треск штанов

Медиум

Злобин Михаил
1. О чем молчат могилы
Фантастика:
фэнтези
7.90
рейтинг книги
Медиум

"Фантастика 2023-123". Компиляция. Книги 1-25

Харников Александр Петрович
Фантастика 2023. Компиляция
Фантастика:
боевая фантастика
альтернативная история
5.00
рейтинг книги
Фантастика 2023-123. Компиляция. Книги 1-25

Гром над Тверью

Машуков Тимур
1. Гром над миром
Фантастика:
боевая фантастика
5.89
рейтинг книги
Гром над Тверью

Идеальный мир для Лекаря 11

Сапфир Олег
11. Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 11

Совок

Агарев Вадим
1. Совок
Фантастика:
фэнтези
детективная фантастика
попаданцы
8.13
рейтинг книги
Совок

Табу на вожделение. Мечта профессора

Сладкова Людмила Викторовна
4. Яд первой любви
Любовные романы:
современные любовные романы
5.58
рейтинг книги
Табу на вожделение. Мечта профессора

Сонный лекарь 4

Голд Джон
4. Не вывожу
Фантастика:
альтернативная история
аниме
5.00
рейтинг книги
Сонный лекарь 4

Огненный князь 4

Машуков Тимур
4. Багряный восход
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Огненный князь 4

Войны Наследников

Тарс Элиан
9. Десять Принцев Российской Империи
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Войны Наследников

Бестужев. Служба Государевой Безопасности. Книга вторая

Измайлов Сергей
2. Граф Бестужев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бестужев. Служба Государевой Безопасности. Книга вторая