Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 45
Текст из файла (страница 45)
Список аргументов в объявлениях таких функций заканчивается многоточием (...), что означает «и может быть еще несколько аргументов». Например: Глава 7. Функции количество строк. Идея состоит в том, что сообщение об ошибке буде~ составляться пз отдельных слов, переданных в качестве строковых аргументов. Список строко- вых аргументов должен заканчиваться нулевым указателем на сЬаг: ех!егп оо!с(еггог(!л! .), ех!ггл сЬаг' !!ои йл1, сдпг[)), 0 с.ч. У б.б.
! 7 сопя! сЬиг'!Уи!! ср = О, иасап!л (!и!агдс, сЬаг'агуо[)) ят!!с6 (агус) ( саяе 1 еггог(О, агуо[О),!Уи!! ср); бгеау; саяе 2: еггог(О, агро[О), агро[1), !Уи!! ср), Ьгеау; де!ли!1: слиг ЬиОег[8); еггог (1, агуо [О), 'с, !!оа (агус — 1, ЬиДег), "арг уменглами", !Уи!! ср), Функция !!оа () возвращает символьную строку, соответствующую целому аргументу. Обратите внимание, что использование О в качестве ограни штепа было бы нс переноспмо. Б некоторых реализациях целый ноль и нулевой указатель имеют различные представления. Это является иллюстрацией нюансов и дополнительных сложностей, с которыми приходится иметь дело программисту, ко! да проверка типов отсугссвчет пз-за использования многоточия. Функцию вывода сообщения об ошибке можно определить следующим образом: О «серьезность» отибк~с зо которон 11 следует ограниченная лучевая 11 указателелс последовательность сдаг" оо!д егтог (т! яеоег!!у . ) оа !!ягор; оа я1аг! (ар, яеоегау); ,1,1 подготовка вргументов 1ог („)( сЬаг*р = оа агу(ар, сЬаг*); (ГУз == О) Ьгеау, сегг «р « ' '; 71 очистка аргументов оа еле!(ар); сепг « '~,л'; О (зевес!!у) ехй (яеоегйу), Сначала определен и ннпциализирован па !ья!при помощи вызова за я!аг!().
Макрос оа з!аг! использует в качестве аргументов пмя переменной типа оа !!я! н имя 199 7.7. Указатель на функцию последнего формального аргумента. Макрос оа агй () используется для последовательного извлечения неименованных аргументов. При каясдол1 вызове программист должен указать тип; иа ац! () полагает, что был передан правильный аргумент ланного типа, но, как правило, не существует способа проверить зто.
До выхода из функции, где была использована оа я!аг! (), необходимо осуществить вызов ва епс! (). Причина состоит в том, что иа я!аг!() может модифицировать стек таким образом, что станет невозможен нормальный выход из функции. Все зги модификации уссраняются вызовом оа епс! (), 7.7. Указатель на функцию С функцией можно проделать только две вещи: вызвать ее и получить ее адрес. Указатель, полученный взятием адреса функции, можно затем использовать для вызова функции.(-!апример: иоЫ еггог (я!гсп)! я) (/' ... */) воЫ (*е/с!) (ягг)пу); //уксиатель нафункс(ию ооиЩ е)с! = Ъеггог, е)с! (' ошибка" ), // е/сс указывает на фукнут!ию еггог 0 вызов еггог ~срез е/с! // правильно О тоже правильно — означает то же сизые, О нпю и сьеггог иоы (У)) (я!над) = с еггог; иоЫ (*)2) (ясгспу) = еггог; ооЫР() ( /! ("Ъаяа"), ('~1) (" Магу Розе"); // привольно // тоже правильно Лргументы указателей на функцию объявляются точно так же, как и аргументы са- мых функций.
При присваивании типы функций должны в точности совпадать. на- пример: 0 указатель на иоЫ(я)ппу) // иоЫ !я!с)пу) // т! Панну) // аоЫ (и )*) ооЫ(*рЯ (яггтпу1 ио)с(/1 (ягг)пу), т !)2 (я!с)пи), ао)с! !З' ()пс*), оойЩ р/= ел/! р/= Ел/2, р/= й/у; // правильно // ошибка: не тот возвраи(аеяыб тип //ошибкас не тот тип иргументи Компилятор распознает, что е/с! является указателем и вызовет функцию, на кото- рую он указывает. То есть, разыменование указателя на функцию при помощи опера- тора * является необязательным.
Лналогично, необязательно пользоваться $ для по- лучения адреса функции: Глава 7. Функции 200 О правильно 0 ошиски: не тот ппи аргуяента ллл ошибка: присваивание иолд переменной т1 рй ('Гера~! ру(!), !п1! = рД("Эевс'), Правила передачи аргументов при вызове функций через указателей те же самые, что и при непосредственном вызове функция. Часто принято определять имена для типов указателей на функции, ~тобы избежать постоянного употребления неочевидного синтаксиса их объявлений. Вот примеры из заголовочного файла на некой системе 1))к(1Х: 1урес!еХоо!с!(*олб ТУР)((п1); Оиз <муна!Ь> 1уреь!ей оо!д ('Ялб Ай!б ТУР) (!и1), Яб ТУР вгупа!(т1,51б Айб ТУР), Часто бывает полезен массив указателей на функции. Например, система меню в моем релакторе, управляемом мышью, реализована через массивы указателей на функции, которые выполняют соответствующие операции.
Здесь невозможно описать всю сис- тему в деталях. Охарактернзуем общую идею: 1уреде) оо1д ('РР( (); Рредц орв() =( О кояанди редактировании йси1, йрав1е, йсору, 8леагсЬ ); Ррйл!е орв() = ( 11 фал!ливинг операции йореп, Барреле), Йс!ове, Йшг11е Теперь мы можем определить и проинициализировать указатели для действий, вы- бираемых из меню и связанных с кнопками мыши: РР Ьи11оп2 = ес!!1 орв, РР Ьи11опЗ = П!е орв, В законченном приложении для определения каясдого пункта меню требуется больше информации. 11апрнмер, где-то надо хранить строку с текстом, который будет выводиться. В процессе использования системы назначение кнопок мыши часто меняется в завис имости от контекста.
Эти изменения (частично) реашгзуюсся путем корректировки указателей, связанных с кнопками. Когда пользователь выбирает пункт меню, например пункт 3, с нажатой кнопкой 2, выполняется соответствующая операция: Ьиг(оп2(2] (), Д вызов третьей функции Ьипоп2 Одним нз способов оценки выразительной моши указателей на функции является попытка написать подобный код без них — и без использования их близких (более цивилизованных) родственников — виртуальных функций Я 12,2.6).
Меню можно моднфнцировать во время выполнения, добавляя новые функции в таблицу операторов, Также легко создавать новые меню во время исполнения. Можно использовать указатели на функции для реализации простой формы полпморфных процедур, то есть процедур, которые можно вызывать с объектами нескольких различных типов: гО1 7.7. Указатель на функцию 1урелУе~ ! п1 (*Се 7) (сопя! со!<У*, с оп в1 во!гг"'у оо!<УззогУ (оо!гУ* Ьаяе, всее уп, згее 1эз, СгТстр) Сортировка п элементов вектора Ьазе в порядке возраст<гния с иснользовиниен функ- ггии сравнения, на которую ркизьгвиет стр. Ризлгер элементов равен зз. блей-сортировка (Кпиик тоя 3, стр 84) * ( )ог (!ау вар=и !2; 0<кар; дар /= 2) 7ог(уп1(=кар; !<и, !ь+) уог (гпу у=! — дар, 0<=у, у-= дар) ( угуг обязательное приведение слаг*Ь = в!ау!с саз1<сЬаг'> (Ьаяе); сЬаг'р/= 5+у* зе; улл 5Ьозеууу сЬаг*рД = Ь+ (у виар) ' зз; ллул 5Ьозе у!+дар/ г7(стр(руи, ру) О) ( !у поненягль лгеспгилт ЬазеУуУ О и даве!!идар/: !ос У!п1 Й=О; Й<зз; Ь++) ( сЬ аг 1етр = ру[Ь) ' ру[Ь) =ру0[Ь)' руи[Ь) = уетр; з1гис1 !/еег( сЬаг* пате, сЬаг' !<У; !а1 г(ер1; ЕУзег Ьеас(з[) = ( "Р!1сЬ!е ул.
М., 'БеуЬ! Р.', "Яяутапзй! Т. 6.', "5сЬ гуег Угг. Е .', "ЯсйгиегЖ Е.", 'Кегп!иЬап В. (Г', '<Угпг', ! 1271, 'гао!", 11272, '1Ьлз", ! 1275, пуз., 11274, "пуз, ! 1275, "Ьтй", 11275 Процедура яяог1 () не знает типы объектов, которые опа сортирует; ей известны только количество элементов (размер вектора), размер каждого элемента п функция, которая производит сравнение, Тпп зяогу () выбран таким же, как тпп стандартной функции библиотеки С лувогу (). В реальных программах используется гувогУ (), стандартный алгоритм библиотеки С< а вагу Я 187.1) или специализированные процедуры сортировки. '1'акой стиль кода является обычным при программировании на С, но не может быть назван самым элегантным способом наложения алгоритма на С ье (см.
з 13 3, з 13 5 2). Нашу функцию можно использовать для сортировки таблицы следующим образом: Глава 7. Функции 202 ооЫргшг Ы(()яею о,1пгп) ( )ос ((пг 1=0; 1<п; 1<-.ь) сои1 «о(1).пате « '~т «о(1) 1д « '~1' «о(1) я)ер1 «",и'; Для того чтобы осуществить сортировку, мы сначала должны определить функцию сравнения. Функция сравнения должна возвращать отрицательное значение, если ее псрвый аргумент меньше второго, ноль, если ар1умепты равны, и положительное значение в противном случае: сг сравнение строковых имен ш1стр) (сопясооЫ*р, соли! оо1д'у) гегигп яггстр (я1адс сая1<сопя1 Юяег> ф->пате я1анс сля1<сопя1 Иег'> (у) — >пате); шс стр2 (сопя1 ооЫ' р, сопя1 ооЫ' у) 11 сравнение нокеров (отдела) ( ге1игп я1а1гс сая1<сопя1 Иег"> (р)->дер1 — я1а1)с сая1<сопя1 Юяег"> (у)->дер1, Следующая программа сортирует и выводит; 1п1 та(п () ( сои1 « 'Начальники отделов в алфавитном порп дкейп', яяогт (Ьеадя, б, я(еео) (1)яег), стр1), рг)п1 Ы ~Ьеадя, б); сои1 ''*~п'; сои1 « "Начальники отделов по номерам отделов ~л", яяогт(деадя, б, я1еео7" (1)яег), стр2); ргш1 Ы(беадя,б~; ) Вы можете получить адрес перегруженной функции путем присваивания указателю на функцию п.ли инициализации указателя на функцшо.
В этом случае тпп указате- ля, которому было произведено присваивание, используется при выборе перегру- женной функции. Папрпл1ер: Функция должна вызываться через указатель на функцию с (в точности) правильны- мн тппамп аргументов и возвращаемого значения. 11е производится неявного преоб- разования типов аргументов или возвращаемого значения при присвоении указате- лям илн нх инициализации. Это означает, что )п1стрЗ (сопя1 ту1уре*, сопя1ту1уре 1 является недопустимым аргументом для яяог1 () Причина в том, что разрешение ис- пользования стра в качестве аргумента явог1 () нарушило бы гарантию того, что яяог1 () вызовется с аргументами туй)ре'1см. также б 9.2.5). ооЫД(1п1), шг) (спас), оо1д (*р11) (1п1) = йй (п1 (*р(2) (сваг) = 8ф иоЫ("р)в) (сваг) = КЯ О войди'1п1) ," ,ш11(сваг) 0с о~иивкаснесп4ункуиивосд((сваг) 203 7.8 Макросы 7.8.
Макросы Макросы имеют большое значение в С, по в С-ь+ они используются значительно реже. Первое правило о макросах; не используйте пх, если вы не обязаны этого делать. Практически каждый макрос свидетельствует о недостатке в языке программирования, программее пли программисте. Так как макросы изменяют текст програгпмы до обработки его компилятором, онп создают проблемы для мнопгх инструментов разработки. Поэтому если вы пользуетссь макросами, можете ожидать худшей работы отладчиков, ~ епсраторов списков перекрестных ссылок, профа(перов' и т. д. Если вам необходимо использовать макросы, внимательно прочитайте руководство по вашей реализации препропессора Сь+ и не пытайтесь искать слишколг хитроумных решений.