Г. Шилдт - Полный справочник по C++ (1109478), страница 71
Текст из файла (страница 71)
Эти члены класса еопзгеее фиксированы и могут использоваться во всех производных классах. Однако функция еожззиее(), выполняющая фактическое преобразование, является чисто виртуальной и должна определяться во всех классах, производных от класса еоптаее. Копкретцый смысл функции еотриее() зависит от типа выполняемого преобразоваиия. 876 Часть й. Язык С++ // Применение виртуальнои функции, 41пс1ийе «1овсхеазп> ивзпд патевраае вхйз с1авв сопчехс ( рхохессейз йоиЫе ча11/ йоиЫе ча12; риЫ з.а: сопчехх(йоиЬ1е 1) ( ча11 = ) йоиЬ1е дехсопч() ( хесихп ча12з ) йоиЫе дес1п1Х() ( хесихп ча11з ) // начальное значение. // Преобразованное значение.
чйхеиа1 чозй созприсе() = 0; // Преобразование хитров в галлоны. с1авв 1 хо д : риЫзс сопчехх риЬ11с: 1 хо д(йоиЬ1е з) : сопчехх(з) ( ] чоз.й осирисе() ( ча12 = ча11 / 3.7854з ) // Преобразование шкалы Фаренгейта в шкалу цельсия. с1авв 1 со а ", риЬ1зс сопчехх ( риЬ1з.с з х со а(йоиЬ1е з.): аопчехх(з.) ( ) чоз.й сошрихе() ( ча12 = (ча11-32) / 1.8з ) 1пх шазп() ( аопчехх *р; // указатель на базовый класа. 1 со д 1доЬ(4)з Е го а тсоЬ(70)з // Применение виртуальной функции.
р = 81доЬз соих « р->дехзпвх() « " литров равно р->сошрихе()з соих « р->дессопч() « " галлоновхп"з // 1 со д р = ьхаоЬз аоие « р->дес1п1Х() « " по Фаренгейту равно р->сошрихе()з соис « р->дессопч() « " по Пельсию1п"з // 1 Хо с хехихп Оз ) Глава 17. Виртуальные функции и полиморфизм В этой программе создаются классы 1 ео д и в ео с, производные от класса сопчехе. Эти классы выполняют преобразования объема, измеренного в литрах, в обьем, выраженный в галлонах, а также переводят шюизу температур по Фаренгейту в шкалу по Е1сльсию соответственно.
Кажлый произволный класс замещает функцию соакасееО посвоему, выполняя необходимое преобразование. Однако, несмотря на различие фактических прсобраювании (те. метолов) в классах 1 ео я и е ео с, их интерфейс одинаков. Вирзуальныс функции позволяют очень легко реагировать на новую ситуацию. Прелположим, что в предыдущей программе необходимо предусмотреть преобразование футов в метры, включив его в класс сопзгохе. Преобразование футов в метры с1авя с со сс: рнЫьс сопчегс рыЫ ус: г Ео гс(С(оссЫе 1): сопчетс(1) ( ) чогс) соагрыее() ( ча12 = уа11 / 3.
2В; ): Абстрактные к)ассы и виртуальныс функции позволяют созлавать библиагнеки классов (с!аьз ВЬпцу), носящие обобшс(шыи характер. Любой программист может создать класс, произволный от библиотечного, добавив свои собственные функции. При этом булет сохранен елинообразный интерфейс, определенный базовым классом. Таким образом, библиотечные классы можно алаптировать к новым ситуациям.
В заключение отметим, что базовый класс согп оке служит примером абстрактного класса. Виртуальная функция сояроее() нс определяется в классе еопяете, поскольку в нем нет информации о выполняемом преобразовании. Функция есяхроеоО наполняется конкретным смыслом лишь в произволных классах. Й Сравнение раннего и позднего связывания Прежле чем завершить главу, посвященную виртуальным функциям и динамическому полиморфизму, следует опрелелить два термина, часто используемых в лискуссиях о яз(яке С++ и объектно-ориентированном программировании: раннее связывание (еаг(у Ь(пгйпй) и назднее связывание (1аге Ьйгс)(пя).
Раннее связывание означает собьпия, происходящие на этапе компиляции. По существу, раннее связывание означает, что на этапе компиляции известна вся информация, позволяюгцая выбрать вызываемую функцию. (Иначе говоря, обьект и вызов функции связываются друг с прутом на этапе компиляции.) Примерами раннего связывания являются обычныс вызовы функции (включая стандартные библиотечные функции), вызовы перегруженных функций и операторов. Основное преимушество раннсп) связыва~(ия — эффективность. Поскольку вся информация о вызываемой функции на этапе компиляции уже известна, сам вызов функции происхолит очень быстро.
Г!азднее связывание является антиполом раннего. В языке С++ позднее связывание означает, что фактический выбор вызываемой функции осуществляется только в холе выполнения программы. Основным средством позднего связывания являются виртуальные функции. Как известно, выбор вызываемой виртуальной функции зависит от типа указателя или ссылки, с помощью которых оца вызывается. Поскольку в большинстве случаев на этапе компиляции эта информация отсутствует, связывание объекта и вызова функции откладывается ло выполнения программы.
Основное преимушество позлнсго связывания — гибкость. В отличие от раннего, позлнее связывание позволяет созлавать программу, рсагируюшую на события, происхоляшис в ходе ее выполнения, без использования большого количества кода, предусматривающего всевозможные варианты. Олнако позл(~ес связывание может замедлить работу программы. Часть 11, Язык С++ аблоны — один из наиболее сложных и мощных механизмов языка С++. Их не бы- Ш ло в первоначальной версии языка С++, но через несколько лет они стати его ~котьемлсмой частью, поддерживаемой всеми современными компиляторами.
С помощью шаблонов можно создавать обобщенные функции и классы, которые работают с типом генных, заданным как параметр. Таким образом, олпу и ту же функцию или класс можно применять к разным типам данным, не используя отдельные варианты для кажлого типа. ~ Обобщенные функции Обобщенная функция определяет универсальную совокупность операций, применимых к различным типам лаццых. Тип данных, с которыми работает функция, передается в качестве параметра. Это позволяет применять одну и ту жс функцию к широкому спектру ланных. Как извхтно, многие алгоритмы носят универсальный характер и не зависят от типа данных, которыми они оперируют. Например, для массивон целых и лействительных чисел используется один алгоритм бысгрой сортировки.
С помощью обобщенной функции можно определить природу алгоритма независимо от типа данных. После этого компилятор автоматически генерирует правильный код, соответствующий конкретному типу. По существу, обобщенная функция автоматически перегружает саму себя. Обобщенная функция объявляется с помощью юючевого слона еезвр1аее. Обычное значение слова "!агар!а1е" (шаблон) точно соответствует своему смыслу в языке С++.
Оно используется для соэлания шаблона, который описывает действия функции и позволяет компилятору самол1у уточнять необходимые детали. Определение шаблонной функции выглядит следующим образом. еевр1аее <е1аяя Ттип> тип возвращаемого значении иип функции(список параметров) ! // Тело функции Здесь параметр Ттип залает тип ланных, с которым работает функция. Этот параметр можно испольэовать и внутри функции, олнако при создании конкретной версии обобщенной функции компилятор автоматически подставит вместо него фактический тип. Традиционно обобщенный тип задается с помощью ключевого слова е1аея, хотя вместо него можно применять ключевое слово еурепаве.
В следующем примере демонстрируется обобщенная функция, меняющая местами две переменные. Поскольку процесс перестановки не зависит от типа переменных, его можно описать с помощью обобщенной функции. // Пример ваблоннои $ункции. Мэпо1ос!е <ьояеееав> цяьед лавеяраое яьб; // В!аблон $ункции. Севр1асе <с1аяя Х> уоэс1 янаракяя(Х Ьа, Х аЬ! ! Х ее|ар; севр = а; а=Ь; Ь = еевр; Часть |!. Язык С++ апс ала1п() ( )пх 1=10, 3=20; с)оцЬ1е х=10.
1, у=.23. 3; спах а='х', Ь='з'; соцх « "Исходные значения 1, 3: " « 1 « ' ' « 3 « '1п'; соцх « "Исхолные значения х, у: " « х « ' « у « 'хп'; соцс « "исходные значения а, Ь: " « а « ' ' сс Ь « ' хп"г выарахдв(1, 3); // Перестановка целых чисел. выарахдв(х„ у); // Перестановка действительных чисел. выарахдв(а, Ь)/ // Перестановка символов. соцс « "переставленные значения 1, 1: " « 1 « ' ' « 3 « 'хп'; соцх « "Переставленные значения х, у: " « х « ' « у « 'Ы'г соцс « Переставленные значения а, Ьг " « а « ' ' « Ь « '1п'/ хесцхп О) Рассмотрим эту программу подробнее. Строка й Сеир1асе сс1авв Х> чо(г) выарахдв (Х аа, Х аЬ) сообшает компилятору, что: во-первых, создается шаблон, и, во-вторых, начинается описание обобгценной функции. Злесь параметр х задает обобщенный тип, который впоследствии будет заменен фактическим типом. После этой строки объявляется функция виарахдв(), в которой переменные, поллежашие перестановке, имеют обобщенный тип х.
В функции ваха() функция веарахдв() вызывается для трех разных типов данных: 1пе, йопЬ1е И сьах. Поскольку функция веарахдв() является обобщенной, компилятор автоматически создает три ее версии: для перестановки целых и действительных чисел, а также символов. С шаблонами связано несколько понятий. Во-первых, обобщенная функция (т.е. функция, объявленная с помошью ключевого слова еевр1аее) называется также шабяоннаи функциеи ((етр!а(е Гцпспоп).
Зги термины являются синонимами Конкретная версия обобщенной функции, создаваемая компилятором, называется слециализацией (зрес)а)птлйоп) ияи генерируемой функцией (йепега(ед Гш)сйоп), Процесс генерации конкретной функции называется канкретизациеи ()пмапйапоп) . Иными словами, генерируемая функция является конкретным экземплярол1 обобщенной функции. Поскольку язык С++ не считает конец строки символом конца оператора, разлел Сеа(р1асе В ОПРЕДЕЛЕНИИ Обобщенной функции не обязан находиться в одной строке с именем функции.
Эту особенность иллюстрирует следуюший пример. севр1асе сс1авв х> чоьп выарахдв(Х аа, Х аЬ) ( Х сезар; хепр = а; а = Ь) Ь = сеер; ) В этом случае следует помнить, гго между оператором ееер1аье И НанаЛОЛг ОПрЕ- деления обобшенной функции не должно быть других операторов. Например, следующий фрагмент ошибочен. Глава 18.
Шаблоны 881 // Замещение шаблонной фунхции. «(пс1цс)е <аовстеат» ивхпд пашеврасе вс((г сешр1асе <с1авя х> чойб яшаратдв(х ьа, х аЫ ( х сешр; сешр -- а; а=Ь; Ь = сешр; соцх « "'Внутри функции вшаратдв. 1п"; ) // Эта функция замещает обобщенную версию функции // выарахдя(), предназначенную для перестановки целых чисел. чоаб выаратдв(тпс аа, хпс аЫ ( фпс сешр; сешр = а; а =Ь; Ь = Сешр; соне « "Внутри специализации функции яыаратдя для целых чисел. 1п"; ) фпс шаап() хпх 1=10, 3=20; бонЬ1е х=-10.1, у=23.3г сиат а='х', Ь='з'; соих « "Исходные значения 1, 3: " « х « ' ' « 3 « ' 1п'/ соцс « "исходные значения х, у: " « х « ' ' « у « ' 1п'г соис « "исходные значения а, Ь: " « а « ' ' « Ь « ' 1п'г яыаратдв!1, 3); // Вызов явно перегруженной функции ьшаратдя().