Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 68
Текст из файла (страница 68)
Например: Глава 11. Перегрузка операторов применяется механизм разрешения перегрузки Я 7А). Для любого постфиксното оператора Ф выражение аай интерпретируется либо как аа.орега1огФ (!и1) либо как орега(огР (аа, гп!). Более подробно зто объясняется в 4 11.11. Если определены обе функции, для определения того, какую (возможно, никакую) из них использовать, лог<меняется мечашгзм разрешения перегрузки Я 7А). Оператор может быть обьявлен только с синтаксисом, сушествуюгцем для него в грамматике (6 сьб). Например, пользователь не может определить унарньпй уь или + с тремя операндами. Рассмотрим пример: с!аев Х( гггг глена (с нРявггсьгг укагапгвлелг !!г!в гггг арефа ксниг! унирньш огпфатор Ъ (чей-гпо адрес) (гг бинсгрниг! оператор Ь (и) гг/ поспгфггксныг(инкрешент (г и.
б 1!. 1!) гггг огипокаг три операнда (гг ошибка: упорный оператор) Х' орега1огб(~; Хореги!огб (Л), Хорега1ог+ь (тф Х ирека(огй (Х, Л); Хорста!ос! (); (гг финкс!гггг-не-члегги ,',г префггксний унарньш тгнус !гг б гнарньш' лшнус 1( постфггксныг! декрелен т О ошибка: отсутствует операнд О оигибкаг три оперинда ,ггг оитбкаг унарньгй оператор 2>ь Х орега1ог — (Х), Х орега!ог — (Х, Л) Хорега1ог — (Хй, гп1), Хорега1ог-() Х прего!ог — (Х, Х Л), Х прего!ос А (Л), Оператор Ц описывается в 9 11.8, оператор () — в 5 11.9, оператор — > — в 6 ! 1.10.
опе- раторы ++ и — — в 9 11.11, а операторы выделения и освобождения памяти в 9 6.2.6.2, 9 10А.11 и 9 156. 11.2.2. Предопределенный смысл операторов с1аьвХ( рггоа1е Но поводу определяемых пользователем операторов делается всего несколько предположений. В частности, орега1ог=, орега1огЦ и орега!ог-> должны быть нестатпческими функциями-членами; это гарантирует, что их первый операнд будет )уа)пе (9 бг.9.6). Некоторые встроенные операторы определены таким образом, что они зквивалентны некоторой комбинации других операторов с теми же операндами. Например, если а — целое, ч.+а означает а+=1, что в свою очередь означает а=а+!.
Такая связь не сохраняется в операторах, опрелеляемых пользователем, если только пользователь нс позаботится об атом сам. Например, компилятор не сгенерирует определение У. орега!огь= () из определения Хсорега1огь () и Хсорега1ог= (). Из-за исторической случайности операторы = (прпсваивапие), Ь (адрес) и, (заданнс последовательности; 9 6.2.2) имеют предопределенный смысл, когда применяются к объектам класса. Этот предопределенный смысл может стать недоступным пользователям, если сделать операторы закрьпыми; 11.2.
Операторные функции 313 ооЫ орего бог= (сопИ Хс.'); воЫ ирека! о ей (), ооЫ орега1ог, (сопз1 Хс ), О. ), ооЫз (Ха, Х Ь) 1 а =Ь; с',а; и,6; з'7 о~паука: оператор = является закрытым 0 о~пинка: оператор 8 является зокрытььч 0 ошибка: оператор, являеп~ся закрытыл~ 11.2.3. Операторы и типы, определяемые пользователем Операторная функция моясет быть либо членом, либо иметь по крайней мере один аргумент типа, определяемого пользователем (за исключением функций, замешаюших операторы пезо и с(е1е1е). Это правило гарантирует, что полъзователь не может изменить смысл выражения в случаях, если только оно не содержит объектов типов, определяемых пользователем. В частности, невозможно определить операторную функцию, которая работала бы исключительно с указателями.
Таким образом, С+ ь расширяем (ехсепз(Ые), но не изменчив (пзпсаЫе) (исключения составляют операторы =, с и, для объектов класса). Операторная функция, у которой первый операнд принадлежит к встроенному типу гсьс В 4.1.1), не может являться членом. Например, рассмотрим сложение комплексной переменной аа и целого числа 2, аа+2. При наличии соответствуюн1им образом объявленных функций-членов это выражение может быть проинтерпретировано как аа.орега1ог+ (2), в то время, как 2+аа — не может, поскольку не сушествует класса (йб для которого определен оператор + в смысле 2.орегасог+ (аа). Даже если бы н был такой класс, операции 2+па и па+2 выполняли бы две различные функции.
Так как компилятор не понимает смысл определяемого пользователем оператора+, он не может делать предположений о его коммутативности и интерпретировать 2+аа, в качестве ад+2. Эту проблему легко решить прн помощи функций-не- спецов Я 11.3.2, в 11.5). Перечисления являются типами, определяемыми пользователем, поэтому мы можем ввести для ннх операторы. Например: епит лгау ( зип, топ, сие, тес), сдиДп', вас ), сгау8 прего!ог~-~ (рлауй с() гегигп а = (за1==с() З зип: лгау (с(ь1); Каждое выражение проверяется на отсутствие неоднозначности.
Всегда, когда опре- деляемзяй пользователем оператор предоставляет возможность той илп иной интер- претации, выражение проверяется в соответствии с правилами из (ь 7.4. С другой стороны, операторам можно придать новый смысл, задав соответствукзшие определения. 314 Глава 11, Перегрузка операторов 11.2.4. Операторы в пространствах имен Оператор является либо членом класса, либо определяетгя в каком-либо пространстве имен (возможно в глобальном). Рассмотрим упрощенную версию ввода/вывода строк из стандартной биолнотекн: натеирасеи161 11 рпрои1еннос просп рангтвоим с1аии оя1 еат 1 П" ои1геатй орега1ог <,'сопи1сдаг"~, ех1егп ок1геат сои1; с(аии ясг1пд 1 0- ок1геатй орега1ог - 1ои1геатй, сопк1 ксппЯ; 1пста!п и' сйаг" р = "Здравствуй", иЫ.
«1п(пик ='мир'; ий1нсои1«р «" "с< к с< П'~п"; В результате, естественно, будет выведено "Здравствуй, мирГ'. Но почему? Обрати- те внимание, я не стал делать доступными все среде~за пз яЫ путем икгпа потекрасе иса; Вместо этого я воспользовался префиксом я1<~:: для я1г1щ н сои1. Другими словамп, я «вел себя хорошо» и не стал засорять глобальное пространство имен или какнм-либо другим образом вводить необязательные зависимости. Оператор вывода С-строк (сЬаг') является членом я1ан:оя1геат, поэтому по определению игд: соиг ..
Р означает з1днсои1.орега1ог«ф Однако яЫэоя1геат не имеет функции-члена для вывода яЫся1г(пд, поэтому яссь, сои1 «я овна гает орега1ог<' 1'исйнсои1, к! Поиск операторов, определяемых в пространствах имен, также как и поиск функций (з 8.2.б), осуществляется на основе типов их операндов. В частности, сои1находится в пространстве имен яЫ, поэтому яЫ включается в рассмотрение прн поиске подходящего определения «. В результате, компилятор находит и использует: кЫ.орегагог«1яЫ .оз1геатй, сопз1иЫси1ппИй~ 11 3. Тип комплексных чисел Рассмотрим бинарный оператор Ю. Если х имеет тип Х, а у имеет тип У, правила разрешения выражения х ну применяются следующим образом: если Хявляется классом, выяснить, определяется ли орега1огй в качестве члена класса Х, либо базового классаХ; просмотреть объявления орега1огФ в контексте, окружающем хну; ' если Хопределен в пространстве имен Л', поискать объявления орега1огФ вЛ1; если Уопределен в пространстве имен М, поискать объявления орега1огР в М.
Может быть найдено несколько об ьявленпй орега1огР и могут быть применены правила разрешения перегрузки Я 7.4) для нахождения наилучшего соответствия, если оно существует. Этот механизм поиска начинает работать, только если у оператора имеется, по крайней мере, один операнд типа, определяемого пользователем. Поэтому будут приняты во внимание преобразования, определяемые пользователем Я 11.3,2, 9 11.4). Обратите внимание, что 1уреде7'просто создает синоним имени и не является типом, определяемым пользователем Я 4.9.7). Унарные операторы разрешаются аналогично.
Обратите внимание, что при просмотре операторов нет преимуществ для членов перед не членами. Это отличается от просмотра именованных функций Я 8.2,б). Результатом недостаточной сокрытости операторов является то, что встроенные операторы всегда лоступны и что пользователи могут придавать новый смысл операторам без модификацин объявления существующего класса. Например, стандартная библиотека потоков ввода/вывода определяет функции-члены «для вывода встроенных членов. Пользователь может определить «для вывода определенных им типов без изменения класса оз1геат Я 21.2,1). 11.3.
Тип комплексных чисел Реализация комплексных чисел, представленная во введении, слишком ограничена, чтобы удовлетворить кого-либо. Например, зная математику, мы ожидаем, что следующее будет работать: ооЫЯ ( сотр1ех а = сотр1ех (1, 2); со~лр1ех 6 = 3, сотр1ех с = а+2 2, сотр1ех о'= 2ьЬ; сотр(сх е = -Ь вЂ” с; Ь = с*2"с, Кроме того, мы хотели бы иметь н несколько дополнительных операторов, таких как == для сравнения, «для вывода п подходящий набор математических функций типа з(л () и здг1 (). Класс сотр1ех является конкретным типом, поэтому при его проектировании мы булем следовать указаниям 9 10.3.
Кроме того, использование комплексной арифметики настолько зависит от операторов, что при определении класса сотр1ех приходится обращаться к большинству основных правил перегрузки операторов. Глава 11. Перегрузка операторов 316 11.3.1. Операторы-члены и не-члены Я предпочитаю сводить к минимуму количество функций, непосредственно манипулируюших представлением обьекта Этого можно добиться определением в те.ле самого класса только тех операторов, которые должны модифицировать значение первого аргумента, таких как +вч Операторы, которые просто выдают новое значение на основе своих аргументов, такие как +, определяются вне класса; они пользуются операторами, имеюшими доступ к представлению: с1авв сотр!ех ( доиЬ!е ге, ип; риЬЛс сотр!ехй орега1ог+= )сотр!ех а); 1) треоувт досгпупа к прсдопп влепи ю сотр1ех орега!ог+ )сотр!ех а, сотр(ех Ь) ( сотр1ех г = а; ге!игп г+= Ь, ) У,) доступ к прсдсгпавпеиию при помощи += При на личии этих объявлений мы можем записать: ио(а) )сотр!ех х, сотр(ех у, сотр(ех з) ( )) г) = орега1ог+(х,орет!ог+(угз) ) Ог2 =х ,Ч г2.вредном=(у) ))'г2 орего1ог(=(з) сотр1ехг) =х+у+х, сотр1ех г2 = х; г2+.= у, г2а=х; (п((пе сотр1ехй сотр1ею,орега1ог+= )сотр(ех а) ге += а ге; (т ~= — аут; ге1игп *!Ь!в; не требует временной переменной для храпения результата сложения н достаточно проста для встраивания.