|
Программирование >> Полиморфизм без виртуальных функций в с++
Глава 17. Пространства имен Всегда рассматривайте то, что вы проектируете, в более широком контексте. Элиэль Сааринвн 17.1. Введение в с имеется единое глобальное пространство для всех имен, что не совсем удачно сочетается с одной функцией, структурой или единицей трансляции. Это порождает конфликты имен. Попытка решить проблему в первоначальном проекте С++ сводилась вот к чему: по умолчанию все имена объявлялись локальными для единицы трансляции, а чтобы они прочитывались в других единицах, следовало явно воспользоваться словом extern. Как отмечалось в разделе 3.12, с одной стороны, этого было мало для решения исходной задачи, с другой стороны, такое решение было недостаточно совместимым. Итак, идея провалилась. Занимаясь механизмом типобезопасного связывания (см. раздел 11.3), я снова вернулся к этой проблеме. Было замечено, что небольшое изменение синтаксиса, семантики и способа реализации конструкции extern С {/*...*/ } позволило бы нам считать, что extern XXX { /* ... */ } означает следующее: имена, объявленные внутри XXX, принадлежат отдельной области действия XXX и доступны в других областях действия лишь при наличии квалификатора XXX::. Следовательно, метод был в точности таким же, как при доступе к статическим членам класса извне этого класса. По разным причинам и прежде всего из-за нехватки времени описанная идея долгое время пролежала в столе и была извлечена на свет во время обсуждений на заседаниях комитета ANSI/ISO в начале 1991 г. Сначала Кит Роуи (Keith Rowe) из Microsoft предложил использовать нотацию bundle XXX { /* ... */ }; для определения именованной области действия и оператор use для импорта имен из области bundle в другую область действия. В дискусси на эту тему приняли участие несколько членов рабочей группы по расширениям, в том числе Стив Дович (Steve Dovich), Дэг Брюк, Мартин ОРиордан и я. В конечном итоге Фолькер Баух (Volker Bauche), Роланд Хартингер (Roland Hartinger) и Эрвин Унру, представляющие компанию Siemens, выдвинули предложение, в котором новых ключевых слов не было: :: XXX ::{/*...*/ }; Это стало поводом для серьезных споров в группе по расширениям. В частности, Мартин ОРиордан показал, что нотация : : приводит к неоднозначному толкованию использования : : для членов классов и глобальных имен. К началу 1993 г. мне удалось сформулировать логически непротиворечивое предложение. Огромный вклад в техническое обсуждение вопроса о пространствах имен внесли Дэг Брюк, Джон Бранс, Стив Дович, Билл Гиббоне, Филипп Готрон, Тони Хансен, Питер Джуль, Эндрю Кениг, Эрик Крон (Eric Krohn), Дуг Макилрой, Ричард Миннер (Richard Minner), Мартин ОРиордан, Джон Скэллер (John Skaller), Джерри Шварц, Марк Террибиль (Mark Terribile) и Майк Вило. Кроме того. Вило ратовал за немедленное воплощение этих идей в конкретное предложение, чтобы иметь нужные средства для решения неминуемой проблемы имен в стандартной библиотеке ISO С++. Включение пространств имен в С++ одобрено на заседании комитета в Мюнхене в июле 1993 г. На заседании в Сан-Хосе (ноябрь 1993 г.) решено использовать пространства имен для контроля за именами в стандартных библиотеках С и С++. 17.2. Для чего нужны пространства имен При наличии только одного глобального пространства имен оказывается трудно писать фрагменты программ, которые будут связываться вместе, и при этом не опасаться возникновения конфликта имен. Например: my.h: char f(char); int f(int); class String { /* ... */ }; your.h char f(char); double f(double); class String { /* ... */ }; Третья сторона не сможет одновременно использовать файлы ту. h и your. h, содержащие такие объявления. Заметим, что некоторые из этих имен будут присутствовать в объектном коде, а программы нередко поставляются без исходных текстов. Отсюда следует, что подмены одного имени другим с помощью макросов и т.п. недостаточно, так как при этом не меняется имя, доступное компоновщику. 17.2.1. Обходные пути Существует несколько обходных путей. Например: my.h: char my f(char); int my f(int); class my String { /* ... */ }; your.h char yo f(char); double yo f(double); class yo String { /* ... */ }; Такой подход не является необычным, но он совершенно неудачен, а если префиксы к тому же не очень короткие, то и неудобен для пользователя. Другая сложность состоит в том, что существует лишь несколько сотен двухбуквенных префиксов, а на С++ уже написаны сотни библиотек. Это одна из самых старых проблем из числа рассматриваемых в данной книге. Программисты, давно работающие на С, вспомнят то время, когда в имена членов структур включались одно-или двубуквенные суффиксы, чтобы избежать конфликтов с членами других структур. Использование макросов может сделать такое решение еще хуже (или лучше, если вам макросы нравятся): my.h: #define my(X) rayprefix ##X char my(f)(char); int my(f)(int); class my(String) { /* ... */ }; your.h #define yo(X) your ##X char yo(f) (char) ,- double yo(f)(double); class yo(String) { /* ... */ }; Идея состоит в том, чтобы разрешить длинные префиксы в именах, видимых компоновщику, оставив короткими имена, используемые в исходно.м тексте. Как и все схемы, основанные на макросах, эта также создает проблемы для инструментальных средств: отслеживать отображение имен должен либо инстру.мент (за счет существенного усложнения), либо пользователь (что усложняет программирование и сопровождение). Альтернативный подход - его обычно предпочитают те, кто не любит макросы, - поместить всю необходимую информацию внутри класса: my.h: class My { public: static char f(char); static int f (int) ; class String {/*...*/};
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |