Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 44
Текст из файла (страница 44)
В подобных случаях можно вводить н удалять локальные объявления ради достижения желаемого результата. Но как всегда, намеренное сокрытие может быть полезным, а непреднамеренное сокрытие оказаться неприятным сюрпризом. Когда требуется распространить перегрузку поверх классовых областей видимости (815.2.2) и областей видимости, связанных с пространствами имен (88.2.9.2), нужно использовать либо объявления из1ии, либо директивы ииил (88.2.2, 88.2.3). См. также 88.2.6. 7.4. Перегрузка имен функций 205 // неоднозначносты !1(сваг) или )7 (1опв) // неоднозначностес )2(сйаг*) или )2(!и(*) В таких случаях следует рассмотреть весь набор перегруженных вариантов функции как единое целое и решить, насколько он логичен с точки зрения семантики функции. Часто разрешить неоднозначность можно простым добавлением еще одного варианта функции.
Например, добавляя !папе во!417дпгп) ()7(1опд(п) ) г ) мы добиваемся разрешения неоднозначности 1(1) в пользу более широкого типа 1ощ зп!. Для разрешения неоднозначности в конкретном вызове можно воспользоваться явным преобразованием типа. Например: )2(таас сам<!и!*> (()) ) Однако это не более, чем паллиатив — в каждом новом вызове все надо повторять заново. Некоторых новичков в программировании на С++ раздражают сообщения компилятора о неоднозначностях.
Более опытные программисты ценят эти сообщения об ошибках, ибо видят в них своевременные предупреждения об ошибках в проектировании. 7.Я.Я. Разрешение в случае нескольких аргументов В рамках имеющихся правил разрешения перегрузки можно быть уверенным в том, что в случаях, когда точность или эффективность вычислений различаются существенно для разных типов данных, выбран будет самый простой вариант функции (алгоритма вычислений). Например: 1пг ром (шг, ш!); йоиЫе рою (йоиЫе, йоиЫе) ! сотр(ех ров (йоиЫе, сотр!ех) ! сотр(ех рою (сотр1ех, 1ш) ! совр!ел ров (сотр(ех, йоиЫе) ! сотр!ех ров (сотр1ех, сотр(ех); В процессе выбора среди перегруженных функций с двумя и более аргументами на основе правил из 57.4 отбираются функции с наилучшими соответствиями по каждому аргументу.
Вызывается в итоге та из них, у которой для одного аргумента соЫ )) (ш! !) )7 (!) ) )2(0) ! ) тоЫ )) (сотр1ех е ) ( !и! ! = рою (2, 2); йоиЫе й = ров(г. О,2. В) ! сотр1ех с22 = рою (2, е) ! сотр1ех г33 = рою(с,2) ! сотр1ех е44 = ров (е, е) ! ) // вызов ров(!т,ии) // вызов рою(йоиЫе,йоиЫе) // вызов ров(йоиЫе,сагир(ех) // вызов рою(сотр!ех,т!) // вызов ров(сотр(ех,сотр(ех) 206 Глава 7. Функции соответствие наилучшее, а требуюшиеся для других аргументов преобразования не хуже необходимых преобразований у остальных функций.
Если такой функции не находится, то вызов отвергается как неоднозначный. Например: гоЫа() ( Иоииа юК = ром (2. О, 2) ! /l еп.ог: ран Г!п((2.0),2) или ром!2.0,аоиЬ(е(2))? ) Здесь вызов неоднозначен, потому что фактический аргумент 2. 0 наилучшим образом соответствует варианту ром МаиЫе, !гаиЫе), а аргумент 2 наилучшим образом соответствует ра!г(шг, уп!) . 7.5. Аргументы по умолчанию Функции обшего назначения обычно имеют больше аргументов, чем это необходимо в простых случаях. Например, функции для конструирования классовых объектов (классовые конструкторы — см. 510.2.3) часто для гибкости обеспечивают несколько возможностей.
Рассмотрим функцию, предназначенную для печати целого. Решение о предоставление пользователю возможности выбрать основание счисления для выводимых чисел кажется вполне разумным, но в большинстве случаев числа печатаются в десятичном виде. Например, программа гаЫ рмп! (ш! га!ие, !и! Ьазе =10) гаЩ О ( рнп! (31 ); ргт! (31, 10); рпп! (31, 16); рг!и! (З1, г); ) выводит следующую последовательность: З1 З1 1Г Ы111 Эффекта от применения аргумента по умолчанию можно добиться и перегрузкой: гоЫрппг(т! га!ие, т! Ьазе) ! Ыйпе гаЫрнпг(!п! га!ие) (рнпг(га!ае,10) ) ) Однако перегрузка менее четко отражает тот факт, что нужна-то единственная функция печати плюс укороченный вариант ее вызова для наиболее типичного случая.
Тип умолчательного аргумента проверяется в месте объявлении функции и вычисляется в месте ее вызова. Умолчательными значениями могут снабжаться только аргументы, стоящие в самом конце списка аргументов. Например: ш< Г(!пг, !п(=0, ела«*=0) ) Ь а!г !пгя(!а!=О, !п«=0, ела«*) ! Ь а««о« Ьм Ь ( !п)=0, шг, ела«* =О); ?? ег«о« 7.6.
Неуказанное число аргументов 207 Обратите внимание на то, что пробел между * и = обязателен (*= означает операцию присваивания; йб.2): 1пг наму(с(заг =0); з7 синтаксическая ошибка Аргумент по умолчанию нельзя ни повторять, ни изменять в той же самой области видимости. Например: воЫГ(!пг х=7) го!бЯ!пг=7); гоЫГ(!пг=8) з г7 еггог: нельзя повторять аргумент по умолчанию ~У еггою другое значение умолчательного аргумента юЫа() ( гоИ5'(1пг х=9) У... 77 о(с' это обьявление скрывает внешние объявления Объявление имени во вложенной области видимости, скрывающее объявление того же имени в объемлющей области видимости, чревато ошибками.
7.6. Неуказанное число аргументов Для некоторых функций бывает невозможно заранее указать количество и типы всех аргументов вызова. Объявления таких функций содержат список аргументов, завершающийся многоточием (е11!рз!з,... ), означающим, что «могут быть еше аргументы», Например: ип рг!п(Г( сонм сваг* ... ) рг!пф'( "Не((о, шаг!а'! ~п" ); Рг!п(у( "МУ пате и «гг«з 9«в~п", Ягв! пате, весенее па»не); рг!п~(" Уой «у«0=5«гз(~п", 2, 3, 5); В процессе интерпретации списка фактических аргументов вызова такие функции должны опираться на информацию, недоступную компилятору. Для функции рг!и(!() первым аргументом служит так называемая управляющая строка (1оппаг згг!пя), содержащая специальные последовательности символов, которые и позволяют функции ргзпеу() корректно обрабатывать последующие аргументы; ая означает «ожидается аргумент типа сйаг'», а ьН означает, что «ожидается аргумент типа (пбн Компилятор, в общем случае, этого знать не может и не может гарантировать, что ожидаемые дополнительные аргументы будут на месте, или что их тип будет корректным.
Например, программа ()1пс1иФе <зййо. !з> !пг та!п () ( рггп9" ("Му пате и ут «г«з~п", 7); Это объявление означает, что при вызове стандартной библиотечной функции рг!п4'() (з21.о) должен быть указан хотя бы один фактический аргумент типа с1»аг*, но также могут быть (а могут и не быть) и иные аргументы. Например: 208 Глава 7. Функции скомпилируется и [в лучшем случае) выдаст что-нибудь странное [попробуйте на практике!). Ясно, что если аргумент не был объявлен, то компилятор не имеет необходимой информации для проверки типов фактических аргументов и их стандартных преобразований. В таких случаях сйаг или зйогг передаются как шб а11оаг передается как ОоиЬ1е.
Не факт, что программист ожидает именно этого. Хорошо спроектированная программа нуждается лишь в минимальном количестве функций, типы аргументов которых определены не полностью. Чаще всего, вместо функций с неопределенными аргументами можно использовать перегрузку функций и аргументы по умолчанию, что гарантирует надежную проверку типов. Функциями с многоточием следует пользоваться лишь тогда, когда и количество аргументов не определено, и их типы неизвестны. Типичнейшим примером таких функций служат функции библиотеки языка С, разработанные до того, как появились их альтернативы на языке С+-»: (пгзрг(пзз'(Е1ЕЕ», сопл( сьаг* ... ); 77 иэ <сз(ауо'г )пз ехес1 (сопзг слог* ...
); 77 иэ Иу1Х эаголовоч. файла Набор стандартных макросов для доступа к неспецифицированным аргументам этих функций определен в файле <сзМагд>. Напишем функцию еггог() для вывода сообщений об ошибках. У этой функции неопределенное число аргументов, из которых первый имеет тип гпг и означает степень серьезности ошибки, а остальные аргументы — строки. Основная идея состоит в том, чтобы составлять сообщение об ошибке из отдельных слов, передаваемых с помощью строковых аргументов. Список строковых аргументов должен оканчиваться нулевым указателем на сйаг: ехзегп»оЫ еггог (Гпг...
); ех(егп слог* йоа (1пб слог [ ] ); 77 см. зб.б(1»1 сопле слог* )»и11 ср=О; 1пз тат (тз а»Ос, сваг* агл» [ ] ) ( за йсл (а»йс) ( сазе 1: еггог (О, агл» [О], )Уи)1 ср); Ьгеай; сазе 2: еггог(О, агд»[О], агд» [1],МиИ ср); Ьгеай; Ые1аи1[п слог Ьифег [8]: еггог (1, агл» [О], "»»1(Ь", йоа (агяс-1, Ьи[)ег), "агдитепгз", ])(ий ср) 77 ... ) Функция йоа () возвращает строковое представление для своего целого аргумента. Отметим, что использование целого значения О для терминирования списка строк не переносимо, ибо на разных системах целочисленный нуль и нулевой ука- 209 7.7. Указатели на функции затель могут иметь разные представления.