Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 74
Текст из файла (страница 74)
То есть, нам требуется что-то вроде следующего: с1авв Р1г 1а Т) Глава 11. Перегрузка операторов 340 // с проверкой иоЫ 12 (Та) ( //ошибка во вреяя вьтолнения: р вне допугтииого диапазона Операторы инкремента и декремента уникальны среди операторов С вЂ” ' — тем, что их можно использовать как в качестве постфиксных, так и префиксных. Следовательно. мы должны опреде.лить как префиксный, так и постфиксный инкремент и декремепт для Р1г 1о Т. Например: // гвязать с л~асс~!воя и ризмера ь' // и начал»ныл значением р // связаьпь с единстввнныл! обьекп!ол, // начальное значение р Ргг 1о 1(1" р), Р1г 1о Т& орегагогь» (); Рег 1о Торегп1ог++ (ьп1); Р1г 1о Т& орегп1ог — (); Р1г 1о Торегагог — ((пс), Т& орега1ог' (); ), Аргумент ьп! используется для указания на постфиксную форму.
Этот си!никогда не будет задеиствован; ар!умент является фиктивным и служит для распознавания префпксной и постфиксной форм. Чтобы запомнить, какая версия орега1ог++ является префиксной, обратите внимание, что она без фиктивного аргумента, точно также, как и все остальные унарные арифметические и логические операторы. Фиктивный аргумент используется только для «необычных» постфнксных++ н —. С использованием Р1г 1о Т предыдущий пример эквивалентен следующему; // с проверкой ооЫ/2 ~(Та) Т и',2001; Р!г 1о Тр(&и(0],и,200), р.орега1ог — (О), р.орегигог* () =- а, // ошибка ви вре.ия выполнения: //р вне дог!успп»ного диапазона р орега!огн- (); рорега1ог () = а; // правильно Завершение класса Р1г 1о Тоставлено в качестве упражнения Я 11.14(19]) Его превращение в шаблон с использованием исключений для сообщений об ошибках во Т и(200], Ргг Го Тр (&и[0], и,200), р "р = а; .Н.р, 'р = а; // правильно с1аззР1г го Т( Т'р, Т* а ггпу, ьпг з1ге, риЫ!с РГГ 1О Т(Тчр, 7 И, !П1З), // префиксный //постфиксный //префиксный // и остфиксный //префиксный 341 11,12.
Класс 81пп9 время выполнения является еще одним упражнением Я 14.12[2]). Примеры опера- торов ее ц — для итераций можно найти в 9 19.3. Шаблон указателя с корректным поведением относительно наследования представлен в 9 13.6.3. 11.12. Класс 81ппд с(аех $1г(пд ( з1гас1 $гер, $гер *сер, с1аев Сге/, //предстивленпе //ссььлка ни спиг рид11с: с1аее Ванде ( ); //для исключении' Также как и другие члены, класс членов (часто называемый вяозкеннылс классогл) мо- жет быть обьявлен в самом классе, а определен позднее: зсгисг $1гслдп$гер ( с/ьаг' в, 1л1 зе; 1п1 п, // указатель на злел(ентп // колонии~пес сильволов // количество обращении $ гер (иц пзг, сои яс сЬаг* р( ( л=1, зе = лзе; з = лею с1ьаг[зя.ь!]; зсгсру (з, р); // зарезервировать место для зовершиюцего нуля -$гер (]( с/е!есе[] з;) О оделить конто, если необходььио $гер" де1 оил сору(] ( В этом разделе изложена более реалистичная версия класса 51г(л~.
Этот класс является минимальной реализацией строк, которая бы меня устроила, В нем воплощена семантика значений, операции посимвольного чтения и записи, проверяемьш и не- проверяемый доступ, потоковый ввод/вывод, символьные строки в качестве литералов, операторы равенства и конкатенации. Класс хранит строку в виде массива символов с ограничивающим нулем в стиле С и использует механизм подсчета ссылок для минимизации операций копирования.
Написание лучшего и/или реализующего больше возможностей класса является хорошим упражнением (9 11.14[7 — 12]). После того, как это сделано, мы можем выбросить наши упражнения и пользоваться строкамп стандартной библиотеки (глава 20). Мой епочтп настоящий» класс 51г(па пользуется тремя вспомогательными классами: Ягер, который позволяет разделять действьжельпое представление между несколькими объектами типа 51г(лд с одинаковымц значениями; Рияде, для генерации исключений в случае выхода за пределы диапазона, и Сге/ — для реализации оператора индексирования, который различает операции чтения и записи: 342 Глава 11.
Перегрузка операторов (/ (и=-=1) ге1игп 11нв; л —, ге1игп пса Згер (зе, з); ооЫ извел (Елгаве, сопвг сдаг' р) ( (/ (вх!= пзх) ( де(еге!)в; В2 = ПЗ2; в = песо сдпг(вх+1)1 ) з тсср у (в, р), ) // нредохриняет от копнровиния ргеоасе Згер (солз1 Згерй), Згерй орега1ог= (солз1 Згерй) Класс Ыгспп обеспечивает ооычный набор конструкторов, деструкторов и операторов присваивания: с1азв ЗГг(пя( ЗЖпд (), Ох="" 51гЕщ(сопзгсдаг"), // х = "идс' Згг1щ (солз1 ЗЫлдй); //х = о16ег Молд Зхппяй орега1ог= (сопзг сваг'~1 ЗсгЕпдй орега1ог= (сопз151ггщй) -ЗИМ(); 0- Наш класс Иг(поимеет семантику значений, То есть, после присваивания з1=в2, две строки в1 и я2 полностью отличны н последующие изменения в одной не оказывают никакого воздействия на другую.
Альтернативой могло служить задание для ЯЫпд семантики указателей. При этом изменения в в2 после вЕ=в2 привели бы к изменению в в1. Для типов с обычнымп арифметическими операциями, таких как комплексные числа, вектора, матрицы и строки, я предпочитаю семантику значений. Однако, дпя того, чтобы позволить себе роскошь семантики значений, класс Яплд реализован в виде дескриптора, управляющего своим представлением, которое конпруется только при необходимости; //знинениел по умолчанию явяяется пртпия строка Згг1пйг.51г(пй () ( гер = пеы Зг ер (О, "'); О копиррюции) конструктор Зптлд 'ЗггЕлд (сопвг 51гглрйх) ххер — >п.н-; гер = х гер; О ризделяепое предстивя ение 343 11.12.
Класс 81ппц 51г!лд.-51тглу () ( (/ ( — гер — >и == д) с1е!еге гер; 51ггпуй 51г(лу..орега1ог=(сопя! 51т(пд1 х) ( х.гер — >(н~-, !Г~( — гер — >л — -= О) с(е1е1е гер; гер = ххер, те!игл *Йии Операции псевдокопирования с аргументалзи сопя! с/зат* введены для того, чтобы разрешить строковые литералы; 5!тля..51гспу (сопя1с(зат'я) гер = пети 5гер,'я1г1ел (я), я); 51г(пуп 51г!лд орета1о! = (сопя1 сваг' я) ( 0 обновить 5гвр // нспользовитль наоми 5гер ге1итл 'Яиц ) Проектирование операторов доступа к строке является сложной проблемой, потому что (в идеале) доступ должен; осуществляться при помощи привычной формы запзп и (то есть с использованием Ц), быть максимально эффективен и осуществлять проверку диапазона.
К сожалению, невозможно иметь все эти свойства одновременно. Я выбрал эффективные операции без проверки диапазона со слегка неудобной формой заппсн плюс чуть менее эффективные проверяелзые операторы с привычной нотациеп: с1аяя 51г!пу ( ио!с/ с(зес(е (1пг!) сопя1( и" (!<О)) гер->ях =!)1Ьгоизрсапуе (); ) ( с(!аг геас( (!п1 1) сопя! ( ге1игп гер — >я(!); ) иоИже(1е ((п1!', сдагс) ( гер=гер->де! ощп сору(), гер — я[!1=с,) Сге/орегагогЦ (за! !) ( с/!есй (1); ге!игл Стсу (*!1!1я, 1); ) с/! от орета1огЦ (тл1 !) сон я1 ( с/зев(с (1); ге!игл гер — >я[1), ) 1п1 яссе () сопИ ( ге1игп гер — >ее; ) 0- (/ (гер-- п == 1) гер — >аяягуг! (я1г1еп (я), я); е(яе ( гер — >а —; тер = пею 5тер (я1г(еп (я), я), // кот!р)1юи(ее присваивиние // зи!пи!пи огл я(=я1 //рпзделяел!ое преоггвовяение Глава 11.
Перегрузка операторов Идея состоит в толк чтобы при использовании обозначения [) производилась провер- ка, по пользователю предоставлена возможность оптимизации путем проверки диа- пазона один раз для нескольких обращений. Например: !п1 Ьав)ь (сапа! $1г!пдй в) !п16 =в. вас((0), салаг !п1 так = з,вьве (), О нвпровсрне,нов варан)ение к в заг (т11=1;!<!пик, !л-ь) Ь"= а.сваг)(!)» 1; ге1игп )л; Например: аа!г!) ($1г!пув, сапв1 51г!пайк); !п1с! = в[l), в[!) = 'с', Д с! = корвга1ог[)( ! ).орвга!ог с!шг() карелл!о![) (!) юрека(ог — ('г') 0 с2 = г.орега)вг[) ( I) /(ошибка: прпсвапванне перел!внной типа сдаг Ул! г о!лега1аг[) (I ) ='г)' лп1 с2 = г[1); г[1) = 'сГ; ) Обратите внимание, что для нсконстантного объекта, з.орега(от[) (1).
означает Сге! [з, 1). Сложно определьп ь оператор типа [(, который используется и для чтения и для за- писи, в тех случаях, когда неприемлемо просто возвратить ссылку и предоставить пользователю решать, что с ней делать, В нашем случае, подобное решение не под- ходит, потому что я определил $1г!пдтакнм образом, что представление совместно используется различными объектами типа $1г!пд, которые присваивались, переда- валпсь в качестве аргументов и т. д.
до тех пор, пока кто-то не записал в $1ппд. Тог- да и только тогда, представление копируется. Этот метод обычно называется копи- рованиел! при записи (сору-оп-пт)се) или отложенным копированием. Фактическое копирование осуществляется вызовом $1г!пус$гврауе1 ошп сору (). Для встраивания этих функций лоступа определение $гер должно находиться в пх области видимости. Из этого следует, что либо $гер должен быть определен в $1г!пу, либо функции доступа долл;ны быть определены как лп!!пе вне $1ппд и после $1г!яус$гер Я 11.14[2)).