Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 70
Текст из файла (страница 70)
3 7А). Объект, созданный с явным или неявным использованием конструктора в выравкении, является автоматическим и будет уничтожен при первой же возможности (см. й 10.4.10). К левой части оператора, (или — >) не применяется ннкаких неявных преобразований типов, определяемых пользователем. Это происходит даже в тех случаях, когда. задается неявно.
Например: оои1 я (сотр1вх в) 3«г; З.орвга1ог»= (х); 3+=в; 11 яроващио: сотр1вк(3) «а О о~иибко: 3 яв являемся обьвктол кя сосо О оищбкв: 3 ив явля ется объектом класса Следовательно, вы можете отразить тот факт, что оператор требует в качестве левого операнда 1оа1ие, сделав оператор членом. 11.3.6. Литералы Невозможно определить литералы типа, являющегося классом, в том смысле, как 1 2 и 12еЗ являются литералами типа дои61е. Однако в качестве замены можно пользоваться литера. лами встроенного типа, используя функции-члены для их интерпретации. Конструктор с единственным аргументом является стандартным механизмом реаяпзации этой идеи. Если конструктор прост п реализован в виде встроенной функции, вполне разумно рассматривать вызов конструктора с литеральным аргументом в качестве литерала. Например, я рассматриваю сотр!ех(З) как литерал типа сотр1ех, хотя технически это не так.
11.3.7. Дополнительные функции-члены Итак, мы реализовали класс сотр1вх, для которого имеются только конструкторы и арифметические операции. Этого недостаточно для реального использования. На- пример, нам часто потребуется извлечение вещественной и мнимой частей: с(авв сотр1ех 1 боиЫе гв, Ьи; риЬИс боиЫв гва1 1) солвФ(гв1игл гв; ) г(оиЫв ияая () соля! ( гегиго 1т; ) 0- ), В отличие от других членов сотр1вх функцшл-члены геа1 () и 1тая () не модифицируют значение комплексного числа, поэтому их можно обьявить константными, Имея гва1() и 1тасг (), мы можем определить все необходимые операции, не позволяя пм осуществлять непосредственный доступ к представлению класса сотр1ех.
Например: Глава 11. Перегрузка операторов 322 Еп!сае Ьоо! орега1ог== (сотрЕех а, сотр(ех 6) ( ге1игп а геа1 ()==Ьхеа! () ййа!тад()=6!таь () Обратите внимание, что нам понадобилось только чтение вещественной и мнимой частей — потребность в их записи возникает гораздо реже, Есяи требуется <частич- ная модификация, мы можем сделать это следуюгцим образом: оои/(сотр(ехй е, ЙоиЫе гЕ) ( 0- х = сотр1ех (х геа1 (), д); // прнсвошпь д мену гвпг Хороший оптимизатор сп нерирует для этой инструкции одну операцшо присваивания.
11.3.8. Функции-помощники сЕовв сотрЕех ( с(опЫе ге, ип; риЬНс; сотр!ех (с(оиЫе ~О, с(оиЫе 1=0): ге(г), ип (4 () сЕоиЬЕе геа! () сопл! ( ге!игл ге; ) йоиЬЕе ипат () сопв1 (ге1игп ип; ) сотрЕехй орега1ог+= (сотр(ех), сотрЕехй орега1ог+= 'гЕоиЫе), 0-=. '-, /= Кроме того, нам нужен набор функцгй(-помощников: сотр(ех орегагог.ь (сотр!ех, сотр1ех); со>пр(ех орега1ог+ (сптр1ех, с!оиЫе); сотр1ех прего 1ог+ (г(оиЫе, сптр1ех), // унарнии иинус // унарньш ыюг сотр!ех орега1ог- (сотрЕех! сотр!ех орега1ог< (сотрЕех); Ьоо! орега1ог== (сотр1ех, согпр!ех); Ьоо! орегагпг!= (сотр1ех, сотр!ех~; Ев1геатй орега1ог» (Евггеатй, сотрЕехй), О ввод ов1геатй орега1ог«(ов1геатй, сотр!ех); // завод Обратите внимание, что функции- тлены геа! () и Етау () играют значительную роль в определении сравнений.
Следующие функции-помощники также используют геа! () и !тай (). Мы мотли бы реализовать функции, позволяющие пользовате.лю работать в полярных координатах; Если мы соберем все фрагменты вместе, класс сотр1ех будет выглядеть следующим образом: згз 11 4 Операторы преобразования сатр!ех ро!аг (доиЫг гЬа, двиЫе 16в1а), сотр!ех сап!'(сатр!ех), дои6!е ауз (татр!ех>, доиЫе агу(сатр1ех), даи6!е пот>п (сотр1ех), даи61е гга1 (сатр!ех), О дзя удодстза записи >!ос>6!е !>пау (татр!гх), О дзя удобства записи И, наконец, мы должны реализовать гсодходящий набор стандартных математичес- ких функций.
сатр!ех асов (сотр1вх), ситр!ех атп (свтр!вх), готр1ех а1ап гса>пр!вх), С точки зрения пользователя представленный здесь колсплексггый тип почти иденти- чен сатр1ех с1оиЫвз пз есогпр!вхь стандартной библиотеки (ья 22 5). 11.4. Операторы преобразования Использование конструктора для преобразования типа удобно, но может иметь неприятные побо псые эффекты. Конструктор не может осуществить; (1( неявное преобразование из типа, определяемого пользователем, во встроенный тпп (потому что встроенные типы не являются классам п); )2 ( преобразование пз нового класса в ранее определенный класс (не модифицируя объявление старого класса).
Этсг проблемьг можно решить путем определения оператора првобразовангся для и— ходного тслпа Функцгся- глсш Хлорега1ог Т (), где Т вЂ”. имя типа, определяет преобразование Х в Т. Напргллсер, можно определить 6-битовые неотрицательные целые, Тспу, которьи. можно свобс>дпо использовать вместе с целыми в арифметических операциях. с!азз Тиу( сбаг и иасд азз(уп Упс!) ( >Т(!З;077) 16гот Вид папуа (), в=1, ) ри6!!с с!аззВад гапуе(), Тс ну (и1 с) ( азз! уп (!), ) Тспуд, орега1ог= (т11(( азидп (!), ге1ссгп *16!з, ) врвга!аг1п1() сапз1 ( ге1игп И ) Од>унксгссз преобразования в и! ), Диапазон проверяется каждый раз при инициализации Т>пу цельжс, и когда Т!пу присваивается целое.
Проверка дгсапазона не требуется прп копировании Т(пу, поз>емуу копирующпи конструктс>р и присваивание по умолчашпо работают правильно. Для реализации обычных целочисленных операций с переменнымп типа Тту мы опрсделцлп неявное преобразование из Тту в !п1> Ттупорега1огсп1 () Обратите внимание, что преобразуемый тпп является частью имени оператора, и его нельзя повторить в качестве типа возвращаемого значения функции преобразования: Глава 11. Перегрузка операторов 324 //правильно // ошибка Тшу:орега1ог !п1)) соль! ( ге1игл о; ) сл1 Тту .ар его сок !п1 () соле! ( ге1игл о; ) В этом отношении оператор преобразования имеет сходство с конструктором.
При каждом появлении Тту в тех местах, где требуется ш1, используется соответствующий ш1. Например: саста!л () Ттус! = 2; Тспу с2 = 62; Т!пу сЗ = с2-с!; Тшу с4 = сЗ; сп1! = с!вс2; // сЗ=60 // не осусчесгпвляется проверка диапазона (не гпребуется) // 1=64 //выход за предела диапазона, с! нел!охсет равнягпься 64 // 1=-4 // выход за пределы с)напазона, с2 не люхсет равняться — 4 О не огуи!ествляется проверка диапазона (не требуется> с! = с!эс2; !=сЗ вЂ” 64; с2 = сЗ-64, сЗ =с4; Функции преобразования особенно полезны для работы со структурами данных, когда чтение (реализованное оператором преобразования) тривиально, в то время как п)зпсвапванпе н инициализация заметно менее тривиальны.
Тиша !в1геат и ов(геат используют функции преобразования для того, чтобы сделать осмысленными выражения типа тд!!е (с!п»х) сои1«х, // нео днов на яносгп гк орега)огз(1, Тту б) ) или и1(1) и 2 Поэтому чаще имеет смысл пользоваться преобразованиями, определяемыми пользо- вателем, илп операторами, определяемыми пользователем, но не обоими сразу. Операция ввода с!п»х возвращает !в(геат&ь Это значение неявно преобразуется в значение, отражающее состояние ст. Полученное значение теперь может проверяться в шй!Ге (см.
ч 21,3.3). Однако идея определения неявного преобразования одного типа в другой таким образом, что при преобразовании может произойти потеря информации, не слишком хороша. Как правило, лучше не переусердствовать при создании операторов преобразования. При чрезмерном использовании они приводят к неоднозначности. Г!одобная неоднозначность обнаруживается компилятором, но, тем не менее, от нее бывает трудно избавиться.
Вероятно, лучше сначала осуществлять преобразование при помощи именованных функций типа Хстайе !п1(). Если подобная функция становится слишком епопулярнойь, так что ес использование становится неэлегантным, ее можно заменить оператором преобразования Хсорега1ог !г!1(), чтобы воспользоваться более красивым неявным преобразованием. Если существуют и преобразование, определяемое пользователем, и операторы, определяемые пользователем, может возникнуть конфликт между опрсделяеыымп пользователем и встроенными опера~орами.