Перегрузка специальных операций ⇐ ПредыдущаяСтр 3 из 3
В С++ оператор [] при перегрузке рассматривается как бинарный оператор. Его следует перегружать с помощью функции-члена. Нельзя использовать дружественную функцию. Общая форма функции-оператора operator[]() имеет следующий вид: тип имя_класса::оpеrator[](int i) Параметр не обязан иметь тип int, но поскольку функция operator[]() обычно используется для индексации массива, то в таком качестве обычно используется целое значение. О [3] преобразуется в вызов функции operator[](): operator[](3) В таком случае значение индекса передается функции operator[]() в качестве явного параметра. Указатель this указывает на объект О, тот самый, который вызывает функцию. Можно создать функцию-оператор operator[]() таким образом, чтобы оператор [] можно было использовать как с левой, так и с правой стороны оператора присваивания. Для этого достаточно в качестве возвращаемой величины для operator[]() задать ссылку. #include <iostream.h>
На применение переменных ссылочного типа имеется ряд ограничений:
/* перегрузка унарного оператора с помощью дружественной функции, необходимо использовать ссылочный параметр */ Перегрузка ввода-вывода: Для того, чтобы определить оператор вставки для объекта типа three_d, необходимо определить этот оператор по отношению к классу three_d. Для этого необходимо перегрузить оператор <<. Один из способов показан ниже. // вывод координат X, Y, Z (оператор вставки для three_d) Многие особенности этой функции являются общими для всех функций вставки. Прежде всего обратим внимание, что в качестве возвращаемого значения этой функции объявлен объект типа ostream. Это необходимо для того, чтобы один оператор мог содержать несколько операторов вставки. Далее, функция имеет два параметра. Первым служит ссылка на поток, который фигурирует в левой части оператора <<. Вторым параметром служит объект с правой стороны оператора <<. В самой функции осуществляется вывод трех величин, содержащихся в объекте типа three_d, после чего возвращается поток stream. Следующая короткая программа служит для демонстрации оператора вставки: #include <iostream.h> Если удалить отсюда специфический код класса three_d, то получится общая форма функции вставки, как показано ниже: ostream &operator<<(ostream &поток, тип_класса объект) Остается только определить конкретные действия, выполняемые таким оператором вставки. Обратим внимание на необходимость возвращать stream. Также является приемлемым и, более того, является общей практикой использовать в качестве параметра объект ссылку, а не сам объект. Преимуществом передачи ссылки на объект служит то, что если объект является большим, то гораздо быстрее передать его адрес. Во-вторых, это предотвращает вызов деструктора объекта когда функция вставки возвращает результат. Кажется странным, почему функция вставки объекта типа three_d не реализована в коде наподобие следующего: // ограниченная версия - не использовать В данной версии поток cout вставлен в тело функции, однако надо иметь в виду, что оператор << может применяться к любому потоку. Поэтому необходимо использовать поток, передаваемый функции, для того, чтобы она могла корректно работать во всех случаях. В программе вставки класса three_d перегруженная функция вставки не является членом класса three_d. Действительно, ни функция вставки, ни функция извлечения не могут быть членами класса. Причина заключается в том, что если функция-оператор является членом класса, то левым операндом, неявно передаваемым с использованием указателя this, служит объект того класса, который осуществляет вызов функции-оператора. И нет способа изменить такой порядок. Вместе с тем при перегрузке оператора вставки левым аргументом является поток, а правым аргументом — объект класса. Поэтому перегруженные операторы вставки не могут быть функциями-членами. Тот факт, что функции вставки не могут быть членами класса для действия, на котором они определены, вызывает серьезные вопросы: как перегруженный оператор вставки может получить доступ к частным членам класса? В предыдущей программе переменные х, у и z были публичными, так что оператор вставки имел к ним доступ. Однако защита данных является одной из важнейших особенностей объектно-ориентированного программирования, и требовать, чтобы все данные были публичными, значит противоречить самому духу объектно-ориентированного программирования. Тем не менее данная проблема имеет решение: оператор вставки может быть другом класса. В качестве друга класса, для которого он определен, он имеет доступ к частным данным. Иллюстрация этого имеется в следующем примере: #include <iostream.h> Обратим внимание, что переменные х, у и z являются в данном случае частными членами класса three_d, но тем не менее продолжают быть доступными непосредственно с помощью функции вставки. Объявление операторов вставки и извлечение друзьями классов, для которых они определены, позволяет сохранить неприкосновенным принцип инкапсуляции объектно-ориентированного программирования. Для того, чтобы перегрузить оператор извлечения — экстрактор, используется тот же самый общий подход, что и для перегрузки операторов вставки — инсертеров. Например, следующий экстрактор осуществляет ввод трехмерных координат. Обратим внимание, что он также осуществляет подсказку пользователю. // получение трехмерных значений - экстрактор Экстрактор должен возвращать ссылку на объект типа istream. Первым параметром должна быть ссылка на объект типа istream. Вторым параметром служит ссылка на объект, принимающий ввод. Поскольку это именно ссылка, то второй аргумент может быть модифицирован при вводе информации. Общая форма экстрактора имеет вид: istream &operator>> (istream &поток, тип_класса &объект)
ostream &operator<<(ostream &stream, three_d obj)
Подобно функциям вставки, функции извлечения не могут быть членами класса, на элементах которого они оперируют. Как показано в примере, они могут быть друзьями или просто независимыми функциями. За исключением того, что экстрактор должен возвращать ссылку на объект типа istream, внутри экстрактора можно делать все, что угодно. Однако для лучшей структуризации программы и ее ясности лучше всего ограничить эти действия только операциями ввода.
Задачи
Базовый уровень Перегрузить операции ввода, вывода, преобразование в строку toString 1. Создать класс Point для работы с точками на плоскости. Координаты точки – декартовы. Обязательно должны быть реализованы: перемещение точки по оси Х, перемещение по оси Y, определение расстояния до начала координат, расстояния между двумя точками, сравнение на совпадение и несовпадение 2. Создать класс «банкомат» для работы с выдачей купюр в соответствии с суммой. Класс представлен номиналами и количеством купюр соответствующего достоинства. Реализовать метод определения суммы, а также формирования множества купюр по введенной сумме. 3. Реализовать класс Bill, представляющий собой разовый платеж за телефонный разговор. Класс должен включать поля: фамилия, номер телефона, тариф за минуту разговора, скидка (в процентах), время начала разговора, время окончания, сумма к оплате. Для представления времени использовать класс Time. Реализовать методы извлечения и изменения полей. Время разговора, подлежащее оплате, вычисляется в минутах. Неполная минута считается за полную. Реализовать метод toString для вывода суммы оплаты
Усложненные 4. Создать класс ModelWindow для работы с моделями экранных окон. В качестве полей задаются: заголовок окна, координаты левого верхнего угла, размер по горизонтали, размер по вертикали, цвет окна, состояние «видимое/невидимое», состояние «с рамкой/без рамки». Координаты и размеры указываются в целых числах. Реализовать операции: перемещения окна по горизонтали, по вертикали, изменение высоты и/или ширины окна, изменение цвета, изменение состояния, опрос состояния. Операции передвижения и изменения размера должны осуществлять проверку на пересечение границ экрана. Функция вывода на экран должна индуцировать состояние полей объекта. 5. Реализовать работу с набором (массивом) счетов из задачи 3. ©2015 arhivinfo.ru Все права принадлежат авторам размещенных материалов.
|