Что касается глобального пространства имен в С++
В С++ мы должны будем добавлять материал в глобальное пространство имен с помощью ::
?
Например, при использовании WinAPI, который находится на C, должен ли я сделать ::HANDLE
вместо HANDLE
и ::LoadLibrary
вместо LoadLibrary
? Что говорит С++ об этом? Это вообще хорошая идея, факторинг в вопросах, таких как читаемость и ремонтопригодность?
Ответы
Ответ 1
Поскольку пространства имен не существуют в C, не используйте:: HANDLE для доступа к типу HANDLE.
Использование предпосылки:: для глобального пространства имен является хорошей идеей для удобства чтения, вы знаете, что тип, к которому вы хотите получить доступ, относится к глобальному пространству имен.
Кроме того, если вы находитесь в вложенном пространстве имен и объявляете свой собственный тип HANDLE (например), тогда компилятор будет использовать этот вместо windows.h one!
Таким образом, всегда предпочитайте использовать:: перед именами при работе в вложенном пространстве имен.
Ответ 2
Имена в С++ могут быть квалифицированными и неквалифицированными. Существуют различные правила для квалифицированного и неквалифицированного поиска имен. ::HANDLE
- это квалифицированное имя, а HANDLE
- неквалифицированное имя. Рассмотрим следующий пример:
#include <windows.h>
int main()
{
int HANDLE;
HANDLE x; //ERROR HANDLE IS NOT A TYPE
::HANDLE y; //OK, qualified name lookup finds the global HANDLE
}
Я думаю, что желание выбора HANDLE
vs. ::HANDLE
является вопросом стиля кодирования. Конечно, как показывает мой пример, могут быть ситуации, когда квалификация является обязательной. Таким образом, вы можете использовать ::
на всякий случай, если синтаксис для вас несколько отвратителен.
Ответ 3
Основная интересность заключается в том, что различия с точки зрения компилятора, как уже было сказано, если вы включаете ::
, то вы используете квалифицированный поиск, а не неквалифицированный поиск.
Преимущество использования квалифицированного поиска заключается в том, что он сможет точно определять конкретный символ. Недостатком является то, что он всегда будет определять этот конкретный символ --i.e. он отключит зависящий от аргумента поиск. ADL - большая и полезная часть языка, и, квалифицируя, вы эффективно отключите его, и это плохо.
Учтите, что в глобальном пространстве имен у вас была функция f
, и вы добавили внутри T тип пространства N
. Не считайте, что вы хотите добавить перегрузку f
, которая примет аргумент T
. Следуя принципу интерфейса, вы можете добавить f
в пространство имен N
, так как f
- фактически операция, выполняемая на T
, и она так же относится к типу. В этом случае, если у вас был код, который вызвал (рассмотрите общий код) ::f(obj)
на объект неизвестного типа U
, компилятор не сможет выбрать ::N::f(obj)
как потенциальную перегрузку, поскольку код явно запрашивает перегрузка в глобальном пространстве имен.
Использование неквалифицированного поиска дает вам свободу определять функции, в которых они принадлежат, вместе с типами, которые используются в качестве аргументов. В то время как это не совсем то же самое, рассмотрите использование swap
, если вы квалифицируете std::swap
, тогда он не поднимет вашу ручную развертку void swap( T&, T& )
внутри вашего пространства имен N
...
Я бы только полностью определил идентификаторы, когда компилятор в противном случае не взял бы тот элемент, который я хочу.
Ответ 4
Это во многом вопрос стиля; о проблемах с производительностью или эффективностью говорить не приходится. Это может быть хорошей практикой для крупных проектов и проектов, предназначенных для компиляции на многих разных платформах, поскольку в этих условиях более вероятны столкновения между глобальными именами и именами в пространстве имен.
Ответ 5
Обычно вам не нужно добавлять ::
для глобального пространства имен. (Только в некоторых действительно редких случаях). IMHO вредит читабельности, но, с другой стороны, он, вероятно, не сломает ваш код
Ответ 6
Я поместил весь свой код в пространство имен, и я предпочитаю заголовки С++ над заголовками C, поэтому единственные символы, оставшиеся в глобальном пространстве имен, как правило, относятся к Windows API. Я избегаю вытягивать символы из других пространств имен в текущее пространство имен (например, у меня никогда не было using namespace std;
), предпочитая вместо этого явно квалифицировать вещи. Это соответствует Руководству по стилю Google С++.
Поэтому я получил привычку отбирать вызовы функций WinAPI с помощью ::
по нескольким причинам:
- Последовательность
. Для всего, что находится за пределами текущего пространства имен, я обращаюсь к нему явно (например, std::string
), поэтому почему бы не ссылаться на Windows API явно (например, ::LoadLibraryW
)? Пространство имен Windows API - это глобальное пространство имен.
-
Многие функции WinAPI называются в общем (например, DeleteObject
). Если вы не знакомы с кодом, который вы читаете, вы можете не знать, является ли DeleteObject
вызовом чего-то в текущем пространстве имен или в Windows API. Таким образом, я нахожу, что ::
уточняет.
-
У многих фреймворков Windows есть методы с теми же именами, что и необработанные вызовы. Например, ATL::CWindow
имеет метод GetClientRect
со слегка отличной подписью, чем WinAPI GetClientRect
. В этой структуре общий класс для вашего класса должен быть получен из ATL::CWindow
, поэтому в вашей реализации класса нормально сказать GetClientRect
вызывать унаследованный метод ATL и ::GetClientRect
, если вам нужно вызвать функцию WinAPI. Это не является строго необходимым, так как компилятор найдет правильный, основанный на подписи. Тем не менее, я нахожу, что различие разъясняется читателю.
(Я знаю, что вопрос был не совсем о WinAPI, но пример был в терминах WinAPI.)
Ответ 7
Нет, если у вас нет метода LoadLibrary
в вашем классе, вам не нужно использовать глобальную область. Фактически, вы не должны использовать глобальную область видимости, потому что, если позже вы добавите LoadLibrary
в свой класс, ваши намерения, вероятно, переопределяют глобальную функцию...