Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 199
Текст из файла (страница 199)
): »? см. Ь'14.4.1 Введение всех этих переадресуюших функций довольно утомительно, но не слишком сложно и не очень дорого с точки зрения влияния на производительность программы. сом. Наследование от этого базового класса является мошной технологией. Она применима и к узловым классам, и к абстрактным типам. Как уже сказано, Нап(11е не предназначен для порождения производных классов. Чтобы получить класс, действующий как истинный указатель с подсчетом ссылок, нужно Наи(11е скомбинировать с Р(г из 913.6.3.1 (см. 925.10[2]). Дескриптор, предоставляющий интерфейс, почти идентичный классу, для которого он обеспечивает доступ, часто называют заместителем (ргоху). Это типично для дескрипторов, ссылающихся на удаленные объекты (объекты на удаленных компьютерах).
Глава 25. Роли классов 918 Отметим, что далеко не все функции Яе< нуждаются в блокировке. По моему опыту, зто типично для большинства программ, нуждающихся в пред- и пост-действиях. Блокировка абсолютно всех действий в некоторых системных мониторах приводит к ухудшению параллельного исполнения. Важной причиной для тщательного определения операций дескриптора при перегрузке в нем операции -> является возможность наследования от Яе< сои<го!!ег. Однако многие выгоды от дескрипторов становятся сомнительными, когда в производный класс добавляются поля данных.
В частности, объем контролируемых дескриптором общих данных снижается относительно объема данных, сосредоточенных в каждом дескрипторном объекте. 25.8. Прикладные среды разработки (аррйсабог) Фгап1еччог1(8) Компоненты, построенные из классов, рассмотренных в 925.2 — 925.7, поддерживают проектирование и повторное использование кода, предоставляя как строительные блоки, так и способы их комбинирования; прикладной программист строит каркас программы, в который эти общеупотребительные строительные блоки включаются. Альтернативным (и часто более амбициозным) подходом к поддержке проектирования и повторного использования является автоматическое построение каркаса прилозкения в рамках прикладных сред разработки (арр)(са<!оп ангите<гога), когда программист лишь добавляет к каркасу приложения специфические блоки собственного изготовления.
Классы, из которых автоматически строится общий каркас приложения, обладают столь «жирными» интерфейсами, что вряд ли являются классами в обычном понимании. Они приближают построение законченной программы, если не считать того, что они ничего специфического (характерного для нового приложения) не делают. Все конкретные действия предоставляются непосредственно прикладным программистом. В качестве примера рассмотрим фильтр, то есть программу, которая считывает поток ввода, выполняет какие-то действия с введенными данными, выводит что-то в поток вывода и (возможно) выдает некоторый окончательный результат. Простая среда разработки таких программ обеспечивает набор операций, которые могут потребоваться прикладному программисту: с<ага г"<<<ег ( риЫ<с: е<азз йе<гу ( риы<е: иг<иа! сопз< е«аг* те<зале() (ге<иго О< ) )< г(г<иа! гоЫ з<аг< () ( ) г<г<иа! <и< геа«( ) = О < Ыг<иа! го!«<«г<<е () ( ) г[г<иа! го)й еотри<е () ( ) пг<иа! т< геки<<() = О; 25.8.
Прикладные среды разработки (арр()са((ол (гапгеигог(гз) ггггиа! 1лг гейу(Яейуа т) (сег « т.тетиве() « ' ~п' г ге!игл 2; ) ггггиа! -Г1!гег () ( ) )г Функции, которые должен определять производный класс, объявлены чисто виртуальными; остальные функции определены таким образом, что просто ничего не делают. Среда разработки также обеспечивает главный цикл и рудиментарный механизм обработки ошибок: глгта(п !пор (Гд(ег* р) ( 1ог(г г) ( йу ( р->егагГ() г ггл11е (р->геагг ( ) ) ( р- >сотриге ( ); р->нейе(); ) ге!игл р->гезий () г ) сагсЬ (Ггт!егг г1!ейуа т) ( (Г(гл1 г = р->геггу(т) ) ге!игл г; саге)г (... ) ( сегг « "Га1аг гг!гег еггог'~п" 1 ге!игл 11 ) ) Я (в качестве прикладного программиста) свою собственную часть программы мог бы написать следую(цим образом: с!ат Мут)ггег: риа1(с Гриег 1ейеата 11) оеггеата ос 1 1еи псйаг; риЫгс: тг геагг() (сваг с; 1е.аег(с) г ге!игл 1а.долг!() г ) гоЫсотриге() (псггаг++1 ) гпг гезий() (ое « псггаг « " с!гагас(еге геай'~л"; ге1игп О; ) Му !111ег(1ейеата и, огигеата оо): т(й), ое(оо), пс)гаг(0) ( ) Глава 25 Роли классов 920 и запустить все это на выполнение: !и! та(и () ( Му !!!гег !'(с(и.
сои!); ге(иги та(и (оор («!); ) Естественно, чтобы быть по-настоящему полезной, среда разработки должна предоставлять больше структурных возможностей и намного больше сервисов, чем наш простой пример. В частности, среды разработки обычно являются иерархиями узловых классов. Благодаря тому, что прикладному программисту остается добавлять «листовые» классы (классы-листья), которые прорастают глубоко внутри иерархии, достигается изрядная общность прикладных программ между собой и высокая степень повторного использования служебных сервисов среды разработки. Среды разработки обычно дополняются библиотеками классов, которые нужны прикладному программисту при написании специфического кода «работающих» классов.
25.9. Советы 1. Делайте осознанные решения по способам использования классов (осознанные как проектировщиком, так и пользователем); 925.1. 2. Учитывайте достоинства и недостатки применения разных видов классов; 925.1. 3. Используйте конкретные типы для представления простых независимых концепций; 925.2. 4. Используйте конкретные типы для представления концепций, для которых важна близкая к оптимальной эффективность; 925.2. 5. Не наследуйте от конкретного класса; 925.2.
6. Используйте абстрактные классы для представления интерфейсов в случаях, когда реализации объектов могут варьироваться; 925.3. 7. Используйте абстрактные классы лля представления интерфейсов в случаях, когда разные реализации объектов должны сосуществовать; 925.3. 8. Используйте абстрактные классы для предоставления новых интерфейсов к уже существующим типам; 925.3. 9. Используйте узловые классы там, где схожие концепции разделяют большую часть реализации; 925.4. 10.
Используйте узловые классы для постепенного расширения реализации; 925.4. 11. Используйте КТП для выявления интерфейса объекта; В25.4.1. 12. Используйте классы для ассоциации действий с состоянием (данными); в25.5, 13. Используйте классы для представления действий (операций), которые нужно сохранять, передавать или откладывать их выполнение; э25.5. 25 10 Упражнения 921 14. 15. 16.
17. 18. 25.10. УПРажНЕНИЯ 1. 3. 4. 5. 6. 8. Используйте интерфейсные классы для адаптирования классов к новым спо- собам их использования (без модификации самих классов); 825.6. Используйте интерфейсные классы, чтобы добавить проверки; 825.6.!. Применяйте дескрипторы, чтобы избежать непосредственного использова- ния указателей или ссылок; 825.7. Применяйте дескрипторы дая управления разделяемыми представлениями; 825.7. Применяйте прикладные среды разработок в тех областях, где особенности программ допускают их стандартную структуру; 825.8. (*1) Шаблон 1о из 825.4.1 не работает для встроенных типов.
Исправьте эту ситуацию. (*1.5) Шаблон Напйе из 825.7 не отражает отношений наследования между классами, которыми он управляет. Сделайте так, чтобы он отражал эти зави- симости. То есть чтобы можно было присваивать Нала!е<С(гс!е> объектам типа Нап»Ие<Яларе>, но не наоборот. ('2.5) Отталкиваясь от класса Ягг(ял, определите другой класс, реализующий представление строк с помощью виртуальных функций.
Сравните произво- дительность двух классов. Постарайтесь определить разумный класс, кото- рый оптимально реализовывался бы в форме открытого наследования от строкового класса с виртуальными функциями. ('4) Изучите пару широко используемых библиотек. Классифицируйте их классы в терминах конкретных типов, абстрактных типов, узловых классов, дескрипторных классов и интерфейсных классов. Используются ли в этих библиотеках абстрактные узловые и конкретные узловые классы? Можно ли классы этих библиотек классифицировать как-то иначе? Используются ли жирные интерфейсы? Какие средства применяются для идентификации ти- пов на стадии выполнения? Какова стратегия управления памятью? ("2) Воспользуйтесь средой разработки Лает (825.8) для реализации програм- мы, которая устраняет смежные дублированные слова в потоке ввода, и пере- направляет исправленный поток слов в поток вывода.
(»2) Воспользуйтесь средой разработки Я1гег для реализации программы, ко- торая подсчитывает частоту слов в потоке ввода и помещает в поток вывода пары (слово, частота) в порядке возрастания частоты. ('1.5) Напишите шаблон Яалйе, который принимает тип и диапазон значений элементов в качестве параметров шаблона. ("1) Напишите шаблон Яалле, который принимает диапазон значений в каче- стве параметров конструктора. ('2) Напишите простой строковый класс, который не обрабатывает никаких ошибок. Напишите другой класс, который проверяет доступ к первому. Об- судите все «за» и «против» разделения базовых функций и проверки ошибок. 922 Глава 25.