Современное проектирование на C++. Серия C++ In-Depth, т. 3

Андрей Александреску

C++ In-Depth Box Set First Edition, Vol. 3: Modern C++ Design. Generic Programming and Design Patterns Applied
Andrei Alexandrescu
книга Современное проектирование на C++. Серия C++ In-Depth, т. 3

Где купить книгу

Оглавление
Введение


О новой книге Страуструпа в блоге Виктора Штонда

В книге изложена новая технология программирования, представляющая собой сплав обобщенного программирования, метапрограммирования шаблонов и объектно-ориентированного программирования на C++. Настраиваемые компоненты, созданные автором, высоко подняли уровень абстракции, наделив язык C++ чертами языка спецификации проектирования, сохранив всю его мощь и выразительность. В книге изложены способы реализации основных шаблонов проектирования. Разработанные компоненты воплощены в библиотеке Loki, которую можно загрузить с Web-страницы автора. Книга предназначена для опытных программистов на C++.

336 стр., с ил.; ISBN 5-8459-0571-0; 5-8459-0351-3, 0-201-77581-6; формат 70x100/16; 2002, 3 кв.; Вильямс.



Понравилась книга? Порекомендуйте её друзьям и коллегам:









Оглавление книги "Современное проектирование на C++. Серия C++ In-Depth, т. 3"

Часть I. Методы 23
Глава 1. Разработка классов на основе стратегий 25
Глава 2. Приемы программирования 45
Глава 3. Списки типов 71
Глава 4. Размещение в памяти небольших объектов 99
Часть II. Компоненты 119
Глава 5. Обобщенные функторы 121
Глава 6. Реализация шаблона Singleton 151
Глава 7. Интеллектуальные указатели 179
Глава 8. Фабрики объектов 217
Глава 9. Шаблон Abstract Factory 239
Глава 10. Шаблон Visitor 255
Глава 11. Мультиметоды 281
Приложение. Многопоточная библиотека в стиле минимализма 319
Библиография 329
Предметный указатель 331


ПРЕДИСЛОВИЕ ДЖОНА ВЛИССИДЕСА

Что нового можно сказать о языке С++? Оказывается, очень много. Эта книга посвящена слиянию разных способов программирования - обобщенного программирования, метапрограммирования шаблонов, объектно-ориентированного программирования и разработки шаблонов проектирования - в рамках нового подхода. До сих пор эти направления в программировании развивались изолированно друг от друга, и выгоды, полученные от их объединения, лишь начинают получать достойную оценку. Это слияние открывает новые перспективы для языка С++ не только с точки зрения собственно программирования, но для разработки программного обеспечения в целом. Особенно значительно это повлияет на анализ программного обеспечения и его архитектуру.

Обобщенные компоненты, созданные Андреем, поднимают уровень абстракции настолько высоко, что язык С++ приобретает черты языка спецификаций проектирования (design specification language). При этом в отличие от узкоспециализированных языков проектирования язык С++ сохраняет всю свою мощь и выразительность. Андрей продемонстрировал, как программируются концепции проектирования: синглтоны (singletones), инспекторы (visitors), заместители (proxies), абстрактные фабрики (abstract factories) и т.п. Можно даже настраивать готовые компоненты с помощью шаблонных параметров, не расходуя дополнительного машинного времени. Не нужно выбрасывать кучу денег на разработку новых инструментальных средств или изучать тома методологической тарабарщины. Достаточно иметь надежный современный компилятор (и эту книгу).

Разработчики генераторов кода долгие годы обещали обеспечить их совместимость, но теоретические исследования и практический опыт убедили меня, что достичь этой цели невозможно. Остаются нерешенными проблемы полного обхода дерева поиска, генерации недостаточно качественного кода, негибких генераторов, нечитабельности сгенерированного кода и, разумеется, широко известная проблема, которую можно сформулировать так: "Я не могу вставить этот проклятый код в свою программу". Каждой из этой проблем достаточно, чтобы завести программиста в тупик, а вместе они создают практически непреодолимые препятствия для автоматической генерации кода.

Как было бы хорошо получить все теоретические преимущества автоматической генерации кода - скорость, легкость реализации, сокращенную избыточность, меньшее количество ошибок, одновременно избежав его практических недостатков! Именно это обещает подход, предложенный Андреем. Обобщенные компоненты (generic components) реализуют удачные схемы в виде удобных для использования, поддающихся смешиванию и подходящих для решения задачи шаблонов (mixable-and-matchable templates). Эти шаблоны делают практически то же, что и генераторы кода: создают стандартные фрагменты кода для дальнейшей обработки с помощью компилятора. Отличие заключается в том, что шаблоны позволяют сделать это, не выходя за рамки языка C++. В результате происходит полная интеграция полученного кода с исходным кодом приложения. При этом остается возможность использовать всю мощь языка, расширяя классы, замещая методы и подгоняя шаблоны под свои требования.

Некоторые из описанных приемов программирования довольно трудно понять, особенно метапрограммирование шаблонов, рассмотренное в главе 3. Однако, освоив его, вы сможете постичь всю теорию обобщенных компонентов, которые практически сами себя создают. Эти компоненты описаны в последующих главах. Я думаю, что метапрограммирование шаблонов, изложенное в главе 3, само по себе достойно отдельной книги. Остальные десять глав освещают способы его применения. Несмотря на то что десять глав - это довольно много, ваши инвестиции окупятся сторицей.

Джон Влиссидес (John Vlissides)

ПРЕДИСЛОВИЕ

Возможно, вы держите эту книгу в руках, находясь в книжной лавке, раздумывая, покупать ли ее? А может быть вы пришли в библиотеку и решаете, стоит ли тратить время на эту книгу? Знаю, что у вас нет времени, поэтому буду краток. Если вы когда-либо интересовались, как нужно писать программы высокого уровня на языке С++, как справиться с лавиной мелких деталей, загромождающих даже самую простую программу, или как создать компонент, пригодный для повторного использования, который не нужно разрабатывать заново для каждого нового приложения, то эта книга для вас.

Представьте себе такую картину. Вы приходите с производственного совещания, неся в руках груду диаграмм, на которых нацарапаны ваши комментарии. О'кей, говорите вы, тип события, передаваемого от одного объекта к другому, в любом случае не char. Это - тип int. И вы изменяете одну строку в вашей программе. Интеллектуальный указатель на объект класса Widget работает слишком медленно, его следует сделать неконтролируемым. И вы изменяете еще одну строку. Фабрика объектов должна поддерживать новый класс Gadget, добавленный соседним отделом. И вы снова изменяете одну строку.

Вы закончили разработку своей программы. Компилируете. Связываете. Готово.

Отлично! Не кажется ли вам, что в этом сценарии что-то не так? Намного правдоподобнее выглядит следующее развитие событий. Вы приходите с производственного совещания взмыленный, поскольку вам предстоит выполнить кучу работы. Вы запускаете глобальный поиск. Удаляете фрагмент. Добавляете фрагмент. Делаете ошибки. Исправляете ошибки... В этом и заключается работа программиста, не так ли? Хотя эта книга и не гарантирует вам исполнение первого сценария, она поможет вам пройти несколько шагов в этом направлении. Здесь предпринята попытка представить язык С++ в новом качестве - языка для разработки архитектуры программного обеспечения.

Традиционно код представляет собой наиболее детализированный и сложный аспект программного обеспечения. Исторически, несмотря на существование языков разных уровней, предназначенных для поддержки методологий проектирования (например, объектной ориентации), между проектом программы и ее кодом лежит пропасть. Это обусловлено тем, что в коде должны быть учтены все мельчайшие детали реализации и множество других побочных моментов. Цель программы в большинстве случаев скрывается за множеством подробностей.

В этой книге представлена коллекция пригодных к повторному использованию шаблонов, называемых обобщенными компонентами (generic components), а также способы их разработки. Обобщенные компоненты предоставляют пользователю хорошо известные выгоды, свойственные библиотекам, однако они пригодны для более широкого спектра системных архитектур. Приемы кодирования и реализации сконцентрированы на задачах и моментах, традиционно присущих проектированию, которое обычно предшествует собственно кодированию программ. Благодаря своему высокому уровню абстракции обобщенные компоненты позволяют необычайно выразительно, сжато и легко отображать в коде сложные архитектуры.

В обобщенных компонентах воплощены три ветви программирования: проектирование шаблонов, обобщенное программирование и язык С++. Комбинация этих элементов позволила достичь высокого уровня готовности кода к повторному использованию, условно говоря, как в горизонтальном, так и в вертикальном направлениях. В горизонтальном направлении небольшое количество библиотечного кода позволяет реализовать огромное - в принципе, бесконечное - количество структур и моделей поведения. В вертикальном направлении степень обобщенности этих компонентов делает их пригодными для широчайшего круга программ.

Своим появлением книга обязана проектированию шаблонов, которое позволяет создавать мощные средства решения часто встречающихся задач объектно-ориентированной разработки программ. Проектирование шаблонов - это тщательно отобранные примеры хорошей разработки - рецепты правильных, пригодных к повторному использованию решений задач, возникающих в различных областях. Основной задачей проектирования шаблонов является создание содержательного лексикона (suggestive lexicon) для воплощаемых разработок. Эти шаблоны описывают задачу, ее проверенное временем решение с разными вариантами, а также последствия выбора одного из них. Проектирование шаблонов не связано с конкретными языками программирования. Следуя определенным шаблонам проектирования и комбинируя их друг с другом, компоненты, представленные в этой книге, стремятся охватить как можно более широкий круг конкретных задач.

Обобщенное программирование - это парадигма, в центре которой лежат абстрактные типы, узкий набор функциональных требований и алгоритмы реализации, выраженные в терминах этих требований. Поскольку алгоритмы сами определяют точную и тесную связь с типами, которыми они могут манипулировать, один и тот же алгоритм можно применять для работы с широким спектром типов. Для реализации алгоритмов, приведенных в этой книге, использованы методы обобщенного программирования, позволяющие достичь минимальной специфичности, невероятной лаконичности и эффективности, присущих программам, тщательно разработанным вручную.

В качестве средства реализации в книге используется только язык С++. В этой книге вы не найдете кода, реализующего изящные системы оконного интерфейса, сложных библиотек для сетевого программирования или интеллектуальных механизмов регистрации (logging mechanisms). Вместо этого вы обнаружите массу базовых компонентов, которые облегчают решение как всех описанных выше задач, так и многих других. Для разработки этих компонентов язык С++ крайне необходим. Лежащий в его основе механизм управления памятью, реализованный в языке С, гарантирует быстрое выполнение программ, поддержка полиморфизма позволяет применять приемы объектно-ориентированного программирования, а шаблоны допускают использование невероятных машин, предназначенных для автоматической генерации кода. Шаблоны проходят красной нитью через всю книгу, поскольку они обеспечивают тесное взаимодействие пользователя и библиотеки. Пользователь библиотеки буквально контролирует способ генерации кода, причем этот способ ограничивается самой библиотекой. Предназначение библиотеки обобщенных компонентов - позволять пользователю создавать собственные типы и определять их поведение, а также правильно объединять их с другими обобщенными компонентами. Поскольку при этом используются статические методы, ошибки, связанные со смешиванием и подгонкой соответствующих фрагментов, обычно обнаруживаются на этапе компиляции.

Аудитория

Аудитория, которой предназначена эта книга, состоит из двух частей. К первой категории относятся опытные программисты на С++, желающие овладеть наиболее современными методами создания библиотек. В книге представлены новые мощные идиомы языка С++, обладающие удивительными возможностями, некоторые из которых невозможно было себе представить. Эти идиомы окажут неоценимую помощь при создании библиотек высокого уровня. Для программистов среднего уровня, желающих повысить свою квалификацию, книга также будет полезной, особенно если они проявят определенную настойчивость. Несмотря на то что иногда в книге встречаются довольно сложные фрагменты кода на С++, они всегда сопровождаются подробным комментарием.

Вторая категория состоит из постоянно занятых программистов, которым нужно сделать дело, не тратя лишнего времени на изучение теории. Они могут пропустить наиболее сложные детали реализации и сосредоточить свое внимание на использовании предложенной библиотеки. Каждая глава начинается с подробного введения и заканчивается разделом, посвященным часто задаваемым вопросам. Для понимания и использования компонентов эти разделы окажутся весьма полезными. Компоненты можно изучать независимо друг от друга. Они очень мощны и тем не менее безопасны, и, кроме того, их очень легко применять в своих приложениях.

От читателя требуется хорошее знание языка С++ и желание знать его еще лучше. Следует также иметь представление о шаблонах вообще и стандартной библиотеке шаблонов (STL) в частности.

Знание основных шаблонов проектирования (Гамма и др., 1995) желательно, но не обязательно. Идиомы и шаблоны, применяемые в книге, детально описаны. Однако эта книга посвящена другой теме - в ней не делается попыток максимально обобщить шаблоны проектирования. Поскольку они рассматриваются с точки зрения прагматичного создателя библиотеки, даже читатель, интересующийся в основном шаблонами проектирования, найдет для себя много нового, если захочет.

Библиотека Loki

В книге описывается реальная библиотека Loki, написанная на языке С++. Локи (Loki) - это бог остроумия в скандинавской мифологии, и автор надеется, что оригинальность и гибкость этой библиотеки соответствует названию. Все элементы библиотеки находятся в пространстве имен Loki. В примерах программ пространство имен не указывается, поскольку это увеличило бы размер кода и затемнило его содержание. Библиотеку Loki можно свободно загрузить с Web-страницы http://www.awl.com/cseng/titles/0-201-70431-5.

За исключением части, касающейся потоков, библиотека Loki написана на стандартном языке C++. Увы, это означает, что многие современные компиляторы не смогут работать с ней в полном объеме. Я реализовал и протестировал библиотеку Loki с помощью компиляторов CodeWarrior Pro 6.0 компании Metrowerks и Comeau C++ 4.2.38 (оба компилятора работали под управлением системы Windows). Похоже, что компилятор KAI C++ также не должен иметь с этой библиотекой никаких проблем. Как только поставщики распространят новые, усовершенствованные версии компиляторов, вы сможете эксплуатировать библиотеку Loki полностью.

Код библиотеки Loki, а также примеры, приведенные в книге, используют популярный стандарт кодирования, предложенный Хербом Саттером (Herb Sutter). Я уверен, что вы легко его поймете. Этот стандарт сводится к следующему.

  • Классы, функции и перечислимые типы выглядят так: LikeThis.
  • Переменные и перечислимые значения выглядят так: likeThis.
  • Переменные-члены выглядят так: likeThis_.
  • Шаблонные параметры объявляются с ключевым словом class, если они представляют собой тип, определяемый пользователем (user-defined type), и с ключевым словом typename, если тип является простым (primitive).

Структура книги

Книга состоит из двух основных частей: способы программирования и компоненты. Часть I (главы 1-4) описывает способы программирования на языке С++, используемые в обобщенном программировании и, в частности, для создания обобщенных компонентов. Представлено множество особенностей и способов программирования на языке С++: проектирование, основанное на анализе поведения, частичная специализация шаблонов, списки типов, локальные классы и т.д. Эту часть можно читать последовательно, а затем возвращаться к ней за конкретной информацией.

Часть II организована так же, как и часть I. В ней рассматривается реализация обобщенных компонентов. Здесь нет искусственных примеров. Все описанные компоненты используются в реальных приложениях. Проблемы, ежедневно встающие перед программистами на языке С++, например, интеллектуальные указатели, фабрики объектов и функторы, обсуждаются глубоко и решаются в общем виде. Реализации, приведенные в тексте, ориентируются на основные потребности программистов и предназначены для решения фундаментальных задач. Вместо подробного объяснения, что именно делает тот или иной фрагмент кода, в книге последовательно применяется следующий подход: сначала обсуждается задача, а затем выбирается и реализуется метод ее решения.

Глава 1 посвящена классам стратегий - идиомам языка С++, позволяющим создавать гибкие шаблоны.

В главе 2 обсуждаются основные способы программирования на языке С++, относящиеся к обобщенному программированию.

Списки типов, представляющие собой мощные структуры для манипуляции с типами, реализуются в главе 3.

В главе 4 описывается важный вспомогательный инструмент - механизм распределения памяти для небольших объектов (small-object allocator).

Обобщенные функторы, использующие шаблон проектирования Command, обсуждаются в главе 5.

В главе 6 описываются синглтоны.

Глава 7 посвящена интеллектуальным указателям.

В главе 8 описываются обобщенные фабрики объектов.

Глава 9 посвящена шаблону проектирования Abstract Factory и его реализации.

В главе 10 в общем виде реализовано несколько вариантов шаблона проектирования Visitor.

Механизмы мультиметодов (multimethod engines), представляющие собой решения, ориентированные на использование готовых компонентов, реализованы в главе 11.

БЛАГОДАРНОСТИ

Прежде всего хочу поблагодарить моих родителей за их постоянную заботу.

Следует подчеркнуть, что этой книги, как и большинства моих профессиональных успехов, не было бы без Скотта Мейерcа. С момента нашей встречи на Всемирном конгрессе по С++ (C++ Worlds Congress) в 1998 году Скотт постоянно помогал мне. Он первым с энтузиазмом поддержал мои ранние идеи. Скотт познакомил меня с Джоном Влиссидесом, положив начало нашему сотрудничеству. Он посоветовал Хербу Саттеру сделать меня обозревателем журнала "C++ Report" и привел в издательство Addison-Wesley, практически вынудив начать эту книгу. В конце концов Скотт своими советами и замечаниями помогал мне все время в процессе работы над книгой, разделяя со мной творческие муки.

Выражаю глубокую признательность Джону Влиссидесу, который своими резкими замечаниями убедил меня, что мои решения не идеальны, и помог их улучшить. Глава 9 - его заслуга. Она появилась в книге благодаря постоянным требованиям Джона не останавливаться на достигнутом и искать более удачные решения.

Благодарю П. Дж. Плагера (P. J. Plaeger) и Марка Брианда (Mark Briand), вдохновивших меня писать статьи в журнал "C/C++ Users Journal" в то время, когда я считал обозревателей этого журнала инопланетянами.

Я очень признателен моему редактору Дебби Лафферти (Debbie Lafferty) за ее постоянную поддержку и полезные советы.

Мои коллеги по компании RealNetworks, особенно Борис Джеркуница (Boris Jerkunica) и Джим Кнаак (Jim Knaak), очень помогли мне, создав атмосферу свободомыслия, соперничества и стремления к вершинам мастерства. Я очень благодарен им за это.

Выражаю свою признательность всем участникам форумов comp.lang.c++.moderated и comp.std.c++.Usenet. Эти люди помогли мне лучше понять язык С++.

Я хотел бы выразить свою благодарность рецензентам моей рукописи: Михаилу Антонеску (Mihail Antonecku), Бобу Арчеру (Bob Archer) (моему самому строгому рецензенту), Аллену Бродману (Allen Broadman), Ионату Бурете (Ionut Burete), Мирель Чирита (Mirel Chirita), Стиву Кламагу (Steve Clamage), Джеймсу Коплину (James Coplien), Дугу Хазену (Doug Hazen), Келвину Хенни (Kelvin Henney), Джону Хикину (John Hickin), Говарду Хиннанту (Howard Hinnant), Сорину Джиану (Sorin Jianu), Золтану Кормошу (Zoltan Kormos), Джеймсу Кайперу (James Kuyper), Лизе Липпинкот (Lisa Lippincott), Джонатану Лундквисту (Jonathan Lundquist), Петру Маргиняну (Petru Marginean), Патрику Мак-Киллену (Patrick McKillen), Флорину Михайлу (Florin Mihaila), Сорину Опря (Sorin Oprea), Джону Поттеру (John Potter), Адриану Рапитяну (Adrian Rapiteanu), Монике Рапитяну (Monica Rapiteanu), Брайану Стентону (Brian Stenton), Адриану Стефле (Adrian Steflea), Хербу Саттеру (Herb Sutter), Джону Торйо (John Torjo), Флорину Трофину (Florin Trofin) и Кристи Власяну (Cristi Vlaseanu). Все они внесли свой вклад в улучшение рукописи. Без них мне не удалось бы сделать и половины работы.


Copyright © 1992-2019 Издательская группа "Диалектика-Вильямс"

Rambler  Top100