|
Программирование >> Структурное программирование
Замечание по технике программирования 8.3 Новые возможности ввода-вывода для типов, определенных пользователем, могут быть добавлены в С++ без изменения объявлений или закрытых данных-элементов для классов ostream и istream. Это еще один пример расширяемости языка программирования С++. 8.6. Перегрузка унарных операций Унарную операцию класса можно перегружать как нестатическую функцию-элемент без аргументов, либо как функцию, не являющуюся элементом, с одним аргументом; этот аргумент должен быть либо объектом класса, либо ссылкой на объект класса. Функции-элементы, которые реализуют перегруженные операции, должны быть нестатическими, чтобы они могли иметь доступ к данным класса. Напомним, что статические функции-элементы могут иметь доступ только к статическим данным-элементам класса. Введите номер телефона в виде (123) 456-7890: (800) 555-1212 Был введен номер телефона: (800) 555-1212 Рис. 8.3. Определенные пользователем операции поместить в поток и взять из потока (часть 2 из 2) Этот вызов мог бы затем вернуть ссылку на cin как значение cin phonel, так что оставшаяся часть выражения была бы интерпретирована просто как cin phone2. Это было бы выполнено путем вызова operator (cin, phone2); Операция поместить в поток получает как аргументы ссылку output типа ostream и ссылку num на определенный пользователем тип PhoneNumber и возвраш;ает ссылку типа ostream. Функция operator выводит на экран объекты типа PhoneNumber. Когда компилятор видит выражение cout << phone В main, он генерирует вызов функции operator<<(cout, phone); Функция operator выводит на экран части телефонного номера как строки, потому что они хранятся в формате строки (функция-элемент getline класса istream сохраняет нулевой символ после завершения ввода). Заметим, что функции operator и operator объявлены в class PhoneNumber не как функции-элементы, а как дружественные функции. Эти операции не могут быть элементами, так как объект класса PhoneNumber появляется в каждом случае как правый операнд операции; а для перегруженной операции, записанной как функция-элемент, операнд класса должен появляться слева. Перегруженные операции поместить в поток и взять из потока должны объявляться как дружественные, если они должны иметь прямой доступ к закрытым элементам класса по соображениям производительности. Далее в этой главе мы перегрузим унарную операцию I, чтобы проверять, пуст ли объект класса String. Если унарная операция, такая, как !, перегружена как нестатическая функция-элемент без аргументов и если s - объект класса String или ссылка на объект класса String, то, когда компилятор видит выражение Is, он генерирует вызов s.operator!( ). Операнд s - это объект класса, для которого вызывается функция-элемент operator! класса String. Функция объявляется в описании класса следующим образом: class String { public: int operator!( ) const; Унарная операция, такая, как !, может быть перегружена как функция с одним аргументом, не являющаяся элементом, двумя различными способами: либо с аргументом, который является объектом (это требует копирования объекта, чтобы побочные эффекты функции не оказывали влияния на исходный объект), либо с аргументом, который является ссылкой на объект (никакой копии исходного объекта при этом не делается, но все побочные эффекты этой функции оказывают влияние на исходный объект). Если s - объект класса String (или ссылка на объект класса String), то !s трактуется как вызов орега-torl(s), активизирующий дружественную функцию, не являющуюся элементом класса String, но объявленную в нем следующим образом: class String { friend int operator!( const String &); }; Хороший стиль программирования 8.6 При перегрузке унарных операций предпочтительнее создавать фукции-операции, являющиеся элементами класса, вместо дружественных функций, не являющихся элементами. Дружественных функций и дружественных классов лучше избегать до тех пор, пока они не станут абсолютно необходимыми. Использование друзей нарушает инкапсуляцию класса. 8.7. Перегрузка бинарных операций Бинарную операцию можно перегружать как нестатическую функцию-элемент с одним аргументом, либо как функцию, не являющуюся элементом, с двумя аргументами (один из этих аргументов должен быть либо объектом класса, либо ссылкой на объект класса). Далее в этой главе мы перегрузим бинарную операцию -1-=, указывающую на сцепление двух объектов-строк. Если бинарная операция -t-= перегружена как нестатическая функция-элемент класса String с одним аргументом и если у и Z - объекты класса String , то у += z рассматривается компилятором как выражение y.operator-l-=(z), активизирующее функцию-элемент operator-l-=, объявленную ниже: class String { public: String &operator+=(const String &); Бинарная операция += может быть перегружена как функция, не являющаяся элементом, с двумя аргументами, один из которых должен быть объектом класса или ссылкой на объект класса. Если у и z - объекты класса String или ссылки на объект класса String, то у -1-= z рассматривается как вызов operator+=(y,z), активизирующий объявленную ниже дружественную функцию operator-l-=, не являющуюся элементом: class String { friend String &operator+=(String &, const String &0); 8.8. Учебный пример: класс массив Запись массива в С++ является альтернативой указателям, так что массивы могут служит источником множества ошибок. Например, программа может легко выйти за пределы массива, поскольку С++ не проверяет, не вышли ли индексы из допустимых пределов. Массивы размера п должны иметь номера О, ... , п-1; иных индексов не может быть. Массив целиком не может быть введен или выведен сразу: каждый элемент массива должен быть считан или записан индивидуально. Два массива не могут быть сравнены друг с другом с помощью операций проверки на равенство или операций отношения. Когда массив передается функции общего назначения, обрабатывающей массивы произвольного размера, размер массива должен передаваться как дополнительный аргумент. Один массив не может быть присвоен другому с помощью операции присваивания. Эти и другие возможности, несомненно, кажутся естественными для работы с массивами, но С++ не обеспечивает таких возможностей. Однако, С++ обеспечивает средства для реализации этих возможностей посредством механизмов перегрузки операций. В этом примере мы разработаем класс массив, который выполняет проверку диапазона, чтобы гарантировать, что индексы остаются в пределах границ массива. Класс допускает присваивание одного объекта массива другому с помощью операции присваивания. Объекты этого класса автоматически узнают свой размер, так что при передаче массива функции передавать отдельно размер массива в качестве аргумента не требуется. Массив можно целиком выводить или вводить с помощью операций поместить в поток и взять из потока соответственно. Сравнение массивов можно осуществить с помощью операций == и !=. Наш класс массив использует статический элемент, чтобы отследить количество объектов массивов, которые были созданы в программе. Этот пример отточит ваше понимание абстракции данных. Возможно, вам захочется существенно расширить этот класс массива. Создание класса представляет собой интересный, творческий процесс, стимулирующий интеллект. Программа на рис. 8.4 демонстрирует класс Array и его перегруженные операции. Сначала мы проследим программу драйвер в main. Затем рассмотрим определение класса, каждую функцию-элемент класса и определения дружественных функций. Статический элемент данных arrayCount класса Array содержит количество объектов, образованных во время выполнения программы. Программа начинается с использования статической функции-элемента get ArrayCount,
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |