Г. Шилдт - Полный справочник по C++ (1109478), страница 63
Текст из файла (страница 63)
Эта программа создает класс 1ос, в котором хранятся географические координаты: широта и долгота. В ней перегружается оператор "+". Внимательно изучите эту программу, уделяя особое внимание определению функции орекееох+(]. Взпс1пде <ъсвехеат> свдпд сатеврасе все); с1авв 1сс 1пс 1спйусцде, 1асйспе)е; рп)з11с: 1ос() () 1сс(ьпс 1о, ъпс 1с) ( 1ссд1спе)е = 1сп 1ас1гце)е = 1с; Часть И. Язык С++ чогс) впоы() ( сове « 1оппьсис)е « соис «1вщеи((е « "1п"; ) )ос орегвеок+( 1ос ор2); ) // Очег1овс[ + йог 1ос. 1ос 1ос:.орегвсог+(1ос ор2) ( 1ос совр; севр.
1опд1сиг)е = ор2. 1оп01сис)е + 1оппьсийе; совр.1всзсиде = ор2.1асьсис)е + 1всгсиг)е; гесигп Севр; ) зпс ваьп[) 1ос оЬ1(10, 20), оЬ2( 5, 30); оЫ .впав(); // Выводит нв экран числа 10 20 оЬ2.виси(); // Выводит на экран числа 5 ЗО ОЫ =ОЫ+ОЬ2; оЬ1.виоы(); // Выводит на экран числа 15 50 геситт1 0; ) Как видим, функция орелвсол+(> имеет только один параметр, нссмотрв на то, что она перегружает бинарный оператор. (Как известно, бинарныс операторы имеют два операнда.) Причина заключается в том, что операнд, стоящий в левой части оператора, передастся операторной функции неявно с помощью указателя сыв.
Операнд, стоящий'в правой части оператора, передастся операторной функции через параметр орз, Отсюда следует важный вывод: при перегрузке бинарного оператора вызов операторной функции генерируется объектом, стоящим в левой части оператора.
Как правило, перегруженные операторные функции возвращают объект класса, с которым они работают. Следовательно, перегруженный оператор можно использовать внутри выражений. Например, если бы операторная функция орекаеол+О возвращала объект другого типа, следующее выражение было бы неверным. $ оЫ = оЫ + оЬ2; Длл того чтобы присвоить сумму обьекгов оЫ и оЬ2 объекту оЫ, необходимо, чтобы результат операции + имел тип 1ос. Кроме того, поскольку операторная функция ореласок+() возвращает объект типа 1ос, допускастси следующее выражение: $ (оЬ1+оЬ2).вцоы[); // Выводит нв экран сумму оЬ1+оЬ2 В этой ситуации операторная функцин создает временный объект, который уничтожа- ется после возвращения из функции вцом().
Глава (5. Перегрузка операторов $1пс1иде <1овагеаяо ивхпд папеярасе всдг а1аяя 1оа ьпс 1опд1сиде, 1агтгидег ри)з11с: 1ос() () // Этот конструктор необходим лля создания // временнь1х объектов 1ос(1пс 1д, зпс 1с) ( 1опд1сиде = 1д; 1аегаиде = 1С; уо1д впом() ( соис « 1опд1сиде « соне « 1асьсиде « "хп"г ) орегасог+(1ос ор2) орегасог-(1ос ор2) орегасог=(1ос ор2) орегасог++(); 1ос 1ос 1ос 1ос ): // Перегруженный оператор я лля класса 1оа. 1ос 1ос::орегааог+(1ос ор2) 1ос сверг гетр.1опдьсиде = ор2.1опд1сиде + 1опд1гиде; семр.1ас1еиде = ор2.1асзгиде + 1асьсиде; гееигп сверг ) // Перегруженный оператор — лля класса 1ос.
1ос 1ос::орегаеог-(1ос ор2) ( 1ос евер; // Обратите внимание на порядок операндов веер.1опдъгиде = 1опдьсиде — ор2.1опд1сидег гея1р.1асгеиде = 1ас)аиде — ор2.1ас1сидег гегигп семр; ) Часть Я. Язык С++ Следует понимать, что операторная функция может возврашать объекты любых типов, и что эти типы зависят только от конкретного приложения.
Однако, как правило, операторные функции возврашают объекты классов, с которыми они работает. И еше одно замечание: операторная функция срегаеог+() не модифицирует свои операнды. Поскольку традиционный оператор "+" не изменяет свои операнлы, не имеет смысла предусматривать для функции орегаеог+() иное поведение. (Например, 5+7 равно )2, но при этом слагаемые по-прежнему равны 5 и 7.) Несмотря на то что содержание операторной функции можно определять произвольно, следует оставаться в рамках здравого смысла. Следуюшая программа пополняет класс 1ос тремя перегруженными операторами: "-", "ж*" и унарным оператором "++". Обратите особое внимание на объявления этих функций. // Перегруженный оператор присваиванил длв класса )ос. 1ос 1осззоретасот-(1ос ор2) 1опдъгпйе = ор2.
1огдзтойез 1аеъепйе = ор2.1аез.епйе; тесптзз *спъв; // Возвращает объект, генерирующий вызов ) // Перегруженнь:й грефиксньзй оператор инкрементации ++ // длл класса 1ос. 1ос 1ос::оретаеот++() ( 1опд1епйе++з 1асзсойе++з тесптп *сбъвз ) з.пс лза1п О ( 1ос оЬ1(10, 20), оЬ2( 5„ Зо), оЬЗ(90, 90); оЬ1.вцоы()з оЬ2.впоы()з ++оЬ1з оЬ1.впоиы з // Выводит на экран числа 11 21 оЬ2 = ++оЬ1; оЬ1 вцоы(); // Выводит на экран числа 12 22 оЬ2.виси(); // Выводит на экран числа 12 22 оЬ1 = оЬ2 = оЬЗ; // множественное присваивание оЬ1.вцои()з // Выводит на экран числа 90 90 оЬ2.вцоыО з // Выводит на экран числа 90 90 теситп оз ) Рассмотрим, например, операторную функцию оретаеот-().
Обратите внимание на пордлок ее операндов. Учитывая смысл оператора вычитания, операнд, стоящий в его правой части, вычитается из операнда, стоящего слева. Поскольку вызов операторной функции орегаеог-() генерируется обьектом, стоящим слева от знака "минус", данные объекза ора должны вычитаться из данных объекта, на который ссылается указатель е)з1в. Всегда следует помнить, какой объект генерирует вызов операторной функции. Если оператор " " нс перегружен. лля класса автоматически созлается оператор присваивания по умолчанию, ко~орый созлает побитовые копии объектов. Перегружая оператор " ", можно явно определить оператор присваивания для конкретного класса В данном примере оператор присваивании ничем не отличается от стандартного, однако в других ситуациях оп может выполнять иные действия. Обратите внимание на то, что функция оретатот () ВОЗВРащаст указатель "еЬ1в на объект, сгснерировавший се вызов.
Это позволяет выполнять множественное присваивание объектов, как показано ниже. $ оЬ1 = оЬ2 = оЬЗ; // Кножественное присваивание Глава (5. Перегрузка операторов Перегрузка сокращенных операторов присваивания Сокращенные операторы присваивания (например, "+ *'. "- " и т.п.) также можно перегружать. Рассмотрим операторную функцию орекееок+ () для класса ).оо. 1ос 1осггорегаеог*.=(1ос ор2) 1опд1епс)е = ор2.1опд)епг)е ч 1опд(спс)е; 1ас)спс)е -- ар2.1ае)соде + 1ас)спг)ег геепгп *Оп)вг Ограничения на перегруженные операторы На прил1сненис перегруженных операторов налагается несколько ограничений.
Вопервых, нельзя изменить приоритет оператора. Во-вторых, невозможно изменить количество операндов оператора. (Однако операнд можно игнорировать.) В-третьих, операторную функцию нельзя вызывать с аргументами, значения которых заданы по умолчанию (за исключением оператора вызова функции, который мы рассмотрим немного позднее).
И, в заключение, нельзя перегружать следующие операторы: * о Как неолнократно указывалось, внутри операторной функции можно программировать любые операции. Например, никто не запрещает перегружать оператор "+*' так, чтобы он десять раз записывал в файл с~року "Я люблю С++". Однако эти деиствия сильно отличаются от обычного смысла оператора "+", и вы рискуете разрушить свою программу. Если кто-нибудь станет читать ее и увидит оператор О)зх+ОЬ2, то, естественно, он предположит, что в этом месте складываются два объекта, а не выполняется операция вьпюда в файл.
Следовательно, для значительного отклонения от обычного предназначения оператора должны существовать веские причины. Одна из них — необходимость перегружать операторы "«" и "»". Хотя операторы побитового сдвига не имеют никакого отношения к вводу-выводу, их внешний вид настолько хорошо соответствует этому предназначению„что невозможно устоять перед искушением перегрузить их новым смыслом.
И все же, как правило, лучше оставаться в рамках традиционного смысля. За исключением оператора "=", операторные функции наследуются производными классами. Однако в производном классе каждый из этих операторов снова можно перегрузить. .'4 Перегрузка операторов с помощью дружественных функций Операторы можно перегружать с помощью дружественных функций, не являю- шихся членами класса. Это значит, что дружественные функции нс получают неявного указателя ецдв. Слеловательно. перегруженная операторная функция получает параметры явно. Таким образом, при перегрузке бинарного оператора дружественная функция получает два параметра, а при перегрузке унарного оператора — один. Первым параметром дружественной функции, перегружаюшей бинарный оператор, является его левый операнд, а вторым — правый опсрагщ. В следующей программе функция орекееок+О является дружественной по отношению к классу зоо.
Глава 15. Перегрузка операторов Мзпс1ибе <1овстеав> иззпд павеврасе втб; с1авв 1ос 1пс 1опд1тис)е, 1асусибе; ри)з11с: 1ос() [) // Этот конструктор необходим для создания // временных объектов 1ос(лпт 1д, 1пс 1т) 1опд1тис)е = 1д; 1атзтиде = 1с; ноМ вбои() ( саит «1опд1тис)е « соит «1асзтибе « "1п ) Ет1епс) 1ос оретасот+(1ос ор1, 1ос ор2); // дружественная аукания 1ос оретасот-(1ос ор2); 1ос оретасот=(1ос ор2); 1ос оретатот++(); // Оператор + перегружается с помощью дружественной функиии.
1ос оретатот+(1ос ор1, 1ос ор2) ( 1ос севр; тевр.1опд1тис)е = ор1.1опд1тис(е + ор2.1опд1тиде; тавр.1аттбибе = ор1.1ат1сис)е + ор2.1ат1тибе; тетитп тавр; // Перегруженный оператор — лля класса 1ос. 1ос 1ос::оретатот-(1ос ор2) ( 1ос тавр; // Обратите внимание на порядок операнлов тевр.1опд1тис)е = 1опдзтиде — ор2.1опд1тибеу тавр.1ас1тиде = 1ас1тиде — ор2.1ат1тис)е; теситп тавр; ) // Перегрузка оператора присваивания для класса 1ос. 1ос 1ос.":оретасот=(1ос ор2) ( 1опд1ти()е = ор2.1опд1тис)е; 1ат1сибе = ор2.1ас1сиде; тетитп *СМв; // Возвращается объект, генерирующий вызов '(есть П. Язык ~++ // перегруженный оператор ++ ляя класса 1ос. 1ос 1ос::оретасок++О ( 1опд1сог)е++; 1ас1еиг)е++; гесцтп "сЫе; ) дпе та(п() ( 1ос оЫ (10, 20), оЬ2 ( 5, 30); оЫ = оЫ + оЬ2; ОЫ.
Бион(); теса оп 0; ) На применение дружественных операторных функций налагаются несколько ограничений. Во-первых, с помощью дружественных функций нельзя перегружать операторы "=", "()", *'() *' и "->". Во-вторых, как будет показано в следующем раздсяе, при перегрузке операторов инкрементации и декрементации параметр дружественной функции следует передавать по ссылке. Применение дружественных функций для перегрузки операторов и++" и "—" Если дружественные функции применяются для перегрузки операторов инкрементации и декрсментации, их оперишы следует передавать с помощью ссылок. Это необходимо потому, что дружественная функция нс получает указателя сЫ.а. Предположим, что мы сохраняем первоначальный смысл операторов "++" и "— "'. Следовательно, оператор "'++'*, например, должен модифицировать свой операнд.