|
Программирование >> Полиморфизм без виртуальных функций в с++
your.h class Your ( public: static char f(char); static double f(double); class String { /* ... */ }; К сожалению, и этот подход не лишен многих мелких неудобств. Не все глобальные объявления можно так просто перенести в класс, а некоторые от этого меняют семантику. Например, чтобы избежать изменений семантики, глобальные функции и переменные должны объявляться как статические члены, а тела функций и инициализаторы обычно следует отделять от объявлений. 17.3. Какое решение было бы лучшим? Для решения проблем, связанных с пространством имен, можно воспользоваться разными механизмами. На самом деле, во многих языках имеются, по крайней мере, зачатки средств такого рода. Например, в С есть статические функций, в Pascal - вложенные области действия, в С++ - классы, но более полные решения следует искать в таких языках, как PL/I, Ada, Modula-2, Modula-3 [Nelson, 1991], ML [Wilkstrom, 1987] и СЮ5 [Kiszales, 1992]. Итак, что должен был бы дать языку С++ хороший механизм пространств имен? Продолжительная дискуссия рабочей группы по расширениям при комитете ANSI/ISO позволила составить целый список преимуществ. Вот эти возможности: □ связь с двумя библиотеками без конфликтов и.мен; □ введение имени без конфликта с чужими именами (например, из библиотеки, о которой я никогда не слышал, или неизвестны.ми мне именами из библиотеки, которую, как мне казалось, я знаю); □ добавление новое имя в библиотеку без ущерба интересов пользователей; □ использование имен из двух разных библиотек, даже если эти имена совпадают; □ разрешение конфликтов имен без модификаций самих функций (только за счет манипулирования разрешением имен на уровне объявлений); □ добавление нового имени в пространство имен, не опасаясь вызвать незаметного для пользователя изменения смысла кода, использующего другие пространства имен (мы не можем дать таких гарантий для кода, где используется пространство имен, в которое добавлено имя); □ отсутствие конфликтов между именами самих пространств имен; в частности, реальное (видимое компоновщику) имя может быть длиннее имени, использованного в тексте программы; □ применение механизма пространств к стандартным библиотекам; □ совместимость с С и С++] □ отсутствие издержек на этапе компоновки и во время выполнения при использовании пространств имен; □ лаконичность пространств имен, не меньшая, чем при использовании глобальных имен; □ явное указание в коде, из какого пространства должно быть взято имя. Хорошее решение также должно быть простым. Под простотой я понимаю следующее: □ чтобы механизм можно было сразу использовать для серьезных задач, на объяснение его работы должно уйти не более десяти минут. Чтобы объяснение удовлетворило языковых пуристов, может потребоваться гораздо больше времени; □ разработчик компилятора должен быть способен реализовать этот механизм менее чем за две недели. Разумеется, простоту здесь нельзя понимать строго, ведь людям с разной подготовкой и способностями для усвоения одного и того же материала требуется неодинаковое время. Есть также несколько свойств, которые мы сознательно решили исключить из списка критериев, хотя об их включении часто просили: □ возможность взять два объектных файла с конфликтующими именами и связать их вместе. Это могут сделать инструментальные средства в любой системе, но неясно, как можно было бы реализовать для этого языковую поддержку без значительных затрат. Существует слишком много компоновщиков и форматов объектных файлов, чтобы рассчитывать на их приведение к общему стандарту. Чтобы решение было полезным для С++, оно должно зависеть только от возможностей, предоставляемых практически всеми современными компоновщиками; □ возможность назначать произвольные синонимы именам, используемым в библиотеках. Существующие механизмы - typedef, ссылки и макросы -позволяют это делать в некоторых ситуациях, а универсальным средствам переименования я не доверяю (см. раздел 12.8). Отсюда следует, что механизм устранения неоднозначности должен быть встроен в объектный код авторами отдельных фрагментов програ.ммы. В частности, поставщикам библиотек придется использовать какой-то метод, который дал бы возможность пользователям разрешить неоднозначность. К счастью, именно поставщики библиотек больше всего выигрывают от систематического использования пространств имен. Разумеется, этот перечень можно продолжать, и многие наверняка не согласны с оценкой относительной важности каждого критерия. Тем не менее список дает представление о сложности задачи и о требованиях, которым должно удовлетворять решение. Изложив все критерии, я получил возможность проверить, в какой мере проектирование пространств имен отвечает требованиям простоты. Питер Джуль выполнил первую реализацию за пять дней, а мне менее чем за десять минут удалось объяснить основы механизма пространств имен нескольким пользователям. Заданные вопросы показали, что мои ученики усвоили суть и смогли самостоятельно додуматься до таких применений пространств имен, которые я вообще не объяснял. Итак, механизм оказался достаточно простым. Опыт последующей реализации, обсуждение концепции пространств имен и некоторые их приложения утвердили меня в этом мнении. 17.4. Решение: пространства имен Принятое решение в принципе очень просто. Оно дает четыре новых .механизма; □ механизм определения области действия, обобщающий глобальные объявления в С и С++: пространства имен. Такие области действия разрешается именовать, а к их членам можно обращаться с помощью обьшного для членов класса синтаксиса: namespace name: :meinber name, где namespace name -имя пространства имен, а member name - имя члена. Фактически область действия класса можно считать частным случаем области действия пространства имен; □ механизм определения локального синонима для имени из пространства имен; □ механизм, позволяющий обратиться к одному члену пространства имен, не указывая имя пространства имен, то есть опуская префикс namespace name: : . Это достигается использованием using-объявления; □ механизм, позволяющий обращаться ко всем членам пространства имен, не указывая явно имя самого пространства имен. Достигается использованием using-директивы. Тем самым удовлетворяются все критерии, приведенные в разделе 17.3. Кроме того, решается давний вопрос о том, как обратиться к членам базового класса из области действия производного класса (см. разделы 17.5.1 и 17.5.2). Заодно становится избыточным атрибут static для глобальных имен (см. раздел 17.5.3). Рассмотрим пример: namespace А { void f(int); void f(char); class String { /* ... */ }; ... Имена, объявленные внутри фигурных скобок, принадлежат пространству имен А и не конфликтуют ни с глобальными именами, ни с именами из других пространств имен. Объявления внутри пространства имен (в том числе, и определения) имеют в точности ту же семантику, что и глобальные объявления, но их область действия ограничена этим пространством имен. Программист может использовать такие имена, добавляя явный квалификатор: А::string sl = Annemarie ; void glO { A::f (1);
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |