Возвращение объекта в допустимое состояние особенно важно, если объект мог быть частично изменен прежде, чем произошла ошибка. Например, в данном операторе ввода ошибка могла бы произойти уже после успешного чтения в переменную-член bookNo. В результате значения переменных-членов units_sold и revenue останутся неизменными. Таким образом, новое значение bookNo будет связано с данными прежнего объекта.

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

Проектируя оператор ввода, очень важно решить, что делать в случае ошибки и как вновь сделать объект доступным.

Оповещение об ошибке

Некоторые операторы ввода нуждаются в дополнительной проверке данных. Например, оператор ввода мог бы проверить соответствие формату данных, читаемых в переменную bookNo. В таких случаях оператору ввода возможно понадобится установить флаг состояния потока так, чтобы он означал отказ (см. раздел 8.1.2), хотя с технической точки зрения чтение было успешно. Обычно оператор ввода устанавливает только флаг failbit. Флаг eofbit подразумевал бы конец файла, а бит badbit — нарушение потока. Установку этих флагов лучше оставить библиотеке IO.

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

Упражнение 14.9. Определите оператор ввода для класса Sales_data.

Упражнение 14.10. Опишите поведение оператора ввода класса Sales_data при следующем вводе:

(а) 0-201-99999-9 10 24.95 (b) 10 24.95 0-210-99999-9

Упражнение 14.11. Что не так со следующим оператором ввода класса Sales_data? Что будет при передаче этому оператору данных предыдущего упражнения?

istream& operator>>(istream& in, Sales_data& s) {

 double price;

 in >> s.bookNo >> s.units_sold >> price;

 s.revenue = s.units_sold * price;

 return in;

}

Упражнение 14.12. Определите оператор ввода для класса, использованного в упражнении 7.40 раздела 7.5.1. Обеспечьте обработку оператором ошибок ввода.

<p>14.3. Арифметические операторы и операторы отношения</p>

Как правило, арифметические операторы и операторы отношения определяют как функции не члены класса, чтобы обеспечить преобразования и для левого, и для правого операнда (см. раздел 7.1.5). Эти операторы не должны изменять состояние любого из операндов, поэтому их параметры обычно являются ссылками на константу.

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

// подразумевается, что оба объекта относятся к той же книге

Sales_data

operator+(const Sales_data &lhs, const Sales_data &rhs) {

 Sales_data sum = lhs; // копирование переменных-членов из lhs в sum

 sum += rhs;           // добавить rhs к sum

 return sum;

}

Это определение очень похоже на оригинальную функцию add() (см. раздел 7.1.3). Значение lhs копируется в локальную переменную sum. Затем оператор составного присвоения класса Sales_data (определенный в разделе 14.4) добавляет значение rhs к sum. Функция завершает работу, возвращая копию значения переменной sum.

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

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

Упражнение 14.13. Какие еще арифметические операторы (см. табл. 4.1), если таковые вообще есть, должны, по-вашему, поддержать класс Sales_data? Определите эти операторы.

Упражнение 14.14. Почему оператор operator+ эффективней определять как вызывающий оператор operator+=, а не наоборот?

Упражнение 14.15. Должен ли класс, выбранный в упражнении 7.40 раздела 7.5.1, определять какие-либо арифметические операторы? Если да, то реализуйте их. В противном случае объясните, почему нет.

<p><image l:href="#reader.png"/>14.3.1. Операторы равенства</p>
Перейти на страницу:

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