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