std::cout << totalRevenue/totalCnt << std::endl;

 else

  std::cout << "(no sales)" << std::endl;

 return 0; // означает успех

} else { // транзакции не для того же ISBN

 std::cerr << "Data must refer to the same ISBN"

           << std::endl;

 return -1; // означает неудачу

}

Первый оператор if сравнивает члены bookNo объектов data1 и data2. Если эти члены содержат одинаковый ISBN, выполняется код в фигурных скобках, суммирующий компоненты двух переменных. Поскольку необходимо вывести среднюю цену, сначала вычислим общее количество проданных экземпляров и общий доход, а затем сохраним их в переменных totalCnt и totalRevenue соответственно. Выводим эти значения, а затем проверяем, были ли книги проданы, и если да, то выводим вычисленную среднюю цену за книгу. Если никаких продаж не было, выводим сообщение, обращающее внимание на этот факт.

Упражнения раздела 2.6.2

Упражнение 2.41. Используйте класс Sales_data для перезаписи кода упражнений из разделов 1.5.1, 1.5.2 и 1.6. А также определите свой класс Sales_data в том же файле, что и функция main().

<p><image l:href="#reader.png"/>2.6.3. Создание собственных файлов заголовка</p>

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

Чтобы гарантировать совпадение определений класса в каждом файле, классы обычно определяют в файлах заголовка. Как правило, классы хранятся в заголовках, имя которых совпадает с именем класса. Например, библиотечный тип string определен в заголовке string. Точно так же, как уже было продемонстрировано, наш класс Sales_data определен в файле заголовка Sales_data.h.

Заголовки (обычно) содержат сущности (такие как определения класса или переменных const и constexpr (см. раздел 2.4), которые могут быть определены в любом файле только однажды. Однако заголовки нередко должны использовать средства из других заголовков. Например, поскольку у класса Sales_data есть член типа string, заголовок Sales_data.h должен включать заголовок string. Как уже упоминалось, программы, использующие класс Sales_data, должны также включать заголовок string, чтобы использовать член bookNo. В результате использующие класс Sales_data программы будут включать заголовок string дважды: один раз непосредственно и один раз как следствие включения заголовка Sales_data.h. Поскольку заголовок мог бы быть включен несколько раз, код необходимо писать так, чтобы обезопасить от многократного включения.

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

Краткое введение в препроцессор

Наиболее распространенный способ обезопасить заголовок от многократного включения подразумевает использование препроцессора. Препроцессор (preprocessor), унаследованный языком С++ от языка С, является программой, которая запускается перед компилятором и изменяет исходный текст программ. Наши программы уже полагаются на такое средство препроцессора, как директива #include. Когда препроцессор встречает директиву #include, он заменяет ее содержимым указанного заголовка.

Программы С++ используют также препроцессор для защиты заголовка (header guard). Защита заголовка полагается на переменные препроцессора (см. раздел 2.3.2). Переменные препроцессора способны находиться в одном из двух состояний: она либо определена, либо не определена. Директива #define получает имя и определяет его как переменную препроцессора. Есть еще две директивы, способные проверить, определена ли данная переменная препроцессора или нет. Директива #ifdef истинна, если переменная была определена, а директива #ifndef истинна, если переменная не была определена. В случае истинности проверки выполняется все, что расположено после директивы #ifdef или #ifndef и до соответствующей директивы #endif.

Эти средства можно использовать для принятия мер против множественного включения следующим образом:

#ifndef SALES_DATA_H

#define SALES_DATA_H

#include

struct Sales_data {

 std::string bookNo;

 unsigned units_sold = 0;

 double revenue = 0.0;

#endif

Перейти на страницу:

Похожие книги