|
Программирование >> Операторы преобразования типа
Реализация операторов вывода в выражении с оператором вывода левый операнд определяет поток данных, а правый - объект, записываемый в этот поток: погон объект В соответствии с правилами языка эта конструкция может интерпретироваться двумя способами: поток .орет дХ.от {объент) поток. opera tor ( поток. обьект) Первая интерпретация используется для встроенных типов. Для пользовательских типов должна использоваться вторая интерпретация, поскольку потоковые классы закрыты для расширения. Все, что требуется, - реализовать глобальный оператор для пользовательских типов. Задача решается относительно просто, если при этом не нужен доступ к закрытым членам объекта (но об этом позже). Например, для вывода объекта класса Fraction в формате числитель/знаменатель можно воспользоваться следующей функцией: 1o/fraclout.cpp #1nclude <1ostream> inline std:;ostream8i operator (std:;ostream& strm. const Fraction& f) { strm f.numeratorO 7 f.denominatorO: return strm: Функция выводит числитель н знаменатель, разделенные символом /, в поток данных, передаваемый в аргументе, - файловый, строковый или еще какой-либо. Для поддержки цепочечных операций вывода, а также для совмещения вывода с проверкой состояния потока данных функция возвращает ссылку на поток. У этой простой формы есть два основных недостатка. О Из-за использования в сигнатуре класса ostream функция применима только к потокам данных с типом символов cliar. Если фзт1кция предназначается только для Европы и Америки, проблем не будет. С другой стороны, построить более универсальную версию совсем несложно, поэтому следует по крайней мере рассмотреть такую возможность. О Другая проблема возникает при задании ширины поля. В данном случае результат окажется не тем, который можно было бы ожидать. Ширина поля будет относиться только к ближайшей операции вывода, то есть в данном случае - к выводу числителя. Пример: Fraction vat(16.100): В Германии действует единая ставка НДС=16 std;:cout VAT: \ std::left *std::setw(8) vat std;:endl: Оператор превратился в шаблон функции, параметризованный для всех разновидностей потоков данных. Проблема с шириной поля решается записью в строковый поток данных без указания конкретной ширины. Сконструированная строка затем передается в поток данных, переданный в аргументе. В результате символьное представление дроби выводится одной операцией записи, к которой применяется ширина поля. Например, рассмотрим такой фрагмент: Fraction vatdS.lOO); В Германии действует единая ставка НДС=16Ж std::COut VAT: \ std::left std::setw(8) vat std::endl: Этот фрагмент выведет следующий результат: VAT: 16/100 Реализация операторов ввода Операторы ввода реализуются по тому принципу, что и операторы вывода. Тем не менее при вводе приходится учитывать возможные ошибки чтения. Обычно Эта программа выведет следующий результат: VAT: 16 /100 В следующей версии решены обе проблемы: io/frac2out.cpp #include <1ostream> #1nclude <sstream> template <class charT. class traits> Inline std::bas1c ostream<charT.tra1ts>& operator (std:;baslc ostream<charT.tra1ts>& strm. const Fractions f) /* Строковый поток * - с тем же форматом * - без специальной ширины поля */ std;:bas1c ostr1ngstream<charT.tra1ts> s: s.copyfmt(strm): s.w1dth(0): Заполнение строкового потока s f.numeratorO 7 f.denom1nator(); print string stream strm s.strO; return strm; в фзт1кциях ввода предусматривается особая обработка ситуаций, когда ввод завершается неудачей. При реализации функции ввода приходится выбирать между простотой и гибкостью. Например, в следующей функции используется упрощенный подход - дробь читается без проверки возможных ошибок: io.fracl1n.cpp #1nclude <1ostream> inline std::1stream& operator (std::1stream& strm. Fractions f) { 1nt n. d; strm n: Ввод числителя strm.lgnoreO: Пропуск 7 strm d: Ввод знаменателя f = Fraction(n.d): Присваивание всей дроби return strm; Во-первых, такая реализация подходит только для потоков данных с типом символов char. Во-вторых, она не проверяет, действительно ли два числа разделяются символом /. Другая проблема возникает при вводе неопределенных значений. Если знаменатель прочитанной дроби равен О, ее поведение не определено. Проблема обнаруживается в конструкторе класса Fraction, вызываемом выражением Fraction(n,d). Но зто означает, что ошибки форматирования автоматически обрабатываются внутри класса Fraction. Так как на практике ошибки форматирования обычно регистрируются на уровне потоков данных, лучше установить в этом случае флаг ios base::failbit Наконец, даже неудачная операция чтения может модифицировать дробь, переданную по ссылке. Допустим, числитель был прочитан успешно, а при чтении знаменателя произошла ошибка. Такое поведение противоречит общепринятым правилам, установленным стандартными операторами ввода, и поэтому считается нежелательным. Операция чтения должна либо завершаться успешно, либо не вносить изменений. Ниже приведена усовершенствованная реализация программы, избавленная от этих недостатков. Кроме того, она более универсальна, поскольку благодаря параметризации подходит для любых типов потоков данных: io/frac21n.hpp #include <iostream> template <class charT. class traits> Inline * std;:basic istream<charT.traits>&
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |