Урок 53. Пространства имен

   ⁄ 

 Обновлено 19 Апр 2017

  ⁄   

Этот урок является продолжением урока 24 о конфликтах имен и пространстве std.

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

Рассмотрим пример такого конфликта. boo.h и doo.h – это заголовочные файлы с функциями, которые выполняют разные вещи, но имеют одинаковые имена и параметры.

boo.h:

doo.h:

main.cpp:

Если boo.h и doo.h скомпилировать отдельно, то всё произойдет без инцидентов. Однако, включив их в одну и ту же программу, мы введем две разные функции с одинаковыми именами и параметрами в одну область видимости (глобальную), а это, в свою очередь, приведет к конфликту имен. В результате компилятор выдаст ошибку:

c:\VCProjects\doo.h(4) : error C2084: function 'int __cdecl doOperation(int,int)' already has a body

Вот для решения таких проблем и ввели пространства имен.

Что такое пространство имен?

Пространство имен определяет область кода, в которой гарантируется уникальность всех идентификаторов. По умолчанию глобальные переменные и обычные функции определены в глобальном пространстве имен. Например:

Глобальная переменная g_z и функция boo() определены в глобальном пространстве имен.

В первой программе, когда в main() подключались как boo.h, так и doo.h, обе версии doOperation() были включены в глобальное пространство имен, из-за чего и произошло столкновение имен.

Чтобы избежать ситуаций, когда два независимых фрагмента кода имеют имена, которые конфликтуют друг с другом при совместном использовании, C++ позволяет объявлять собственные пространства имен через ключевое слово namespace. Всё, что объявлено внутри пользовательского пространства имен, принадлежит только этому пространству имен, а не глобальному.

Перепишем заголовочные файлы с первого примера с использованием namespace:

boo.h:

doo.h:

Теперь doOperation() файла boo.h находится в пространстве имен Boo, а doOperation() файла doo.h в Doo. Посмотрим, что произойдет, когда мы перекомпилируем main.cpp:

Результатом будет еще одна ошибка!

C:\VCProjects\Test.cpp(15) : error C2065: 'doOperation' : undeclared identifier

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

Существует два разных способа сообщить компилятору, какую версию doOperation следует использовать: через оператор разрешения области видимости или с помощью using statements (о них мы поговорим в следующем уроке).

Доступ к пространству имен через оператор разрешения области видимости (::)

Первый способ указать компилятору искать идентификатор в определенном пространстве имен — это использовать оператор разрешения области видимости (::). К нему добавляется префикс названия пространства имен, которое нам нужно.

Сообщим компилятору использовать версию doOperation из пространства имен Boo:

Результат:

9

Если бы мы захотели использовать версию doOperation() из Doo:

Результат:

1

Оператор разрешения области видимости хорош, так как позволяет выбрать конкретное пространство имен. Мы даже можем сделать следующее:

Результат:

9
1

Также этот оператор можно использовать без какого-либо префикса (например, ::doOperation). В таком случае мы ссылаемся на глобальное пространство имен.

Пространства имен с одинаковыми именами

Допускается объявление пространств имен в нескольких местах (либо в нескольких файлах, либо в нескольких местах внутри одного файла). Всё, что находится внутри одного блока имён, считается частью только этого блока.

add.h:

subtract.h:

main.cpp:

Работает как и ожидается.

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

Псевдонимы и вложенные пространства имен

Одни пространства имен могут быть вложены в другие пространства имен. Например:

Обратите внимание, поскольку Doo находится внутри Boo, то доступ к g_x осуществляется через Boo::Doo::g_x.

Так как это не всегда удобно и эффективно, C++ позволяет создавать псевдонимы пространств имен.

Стоит отметить, что пространства имен в C++ не были разработаны как способ реализации информационной иерархии – они были разработаны как механизм предотвращения конфликтов имен. Как доказательство этого, вся стандартная библиотека шаблонов находится в единственном пространстве имен std::. Некоторые новые языки (такие как C#) отличаются от C++ в этом отношении.

В целом, следует избегать использования вложенности пространств имен, насколько это возможно.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (12 оценок, среднее: 5,00 из 5)
Загрузка...
Поделиться в:
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *