#c #namespaces #global
#c #пространства имен #глобальное
Вопрос:
В C мы должны добавлять элементы в глобальное пространство имен с ::
помощью?
Например, при использовании WinAPI, который находится на C, должен ли я делать ::HANDLE
вместо HANDLE
и ::LoadLibrary
вместо LoadLibrary
? Что говорит об этом C ? Является ли это вообще хорошей идеей, учитывая такие проблемы, как удобочитаемость и удобство обслуживания?
Комментарии:
1. В более общем плане: рекомендуется ли переопределять имена? Например, если я внутри
namespace foo { ... }
, должен ли я чувствовать себя в безопасности, предполагая, чтоget()
это вызовет myfoo::get()
, или я должен написатьfoo::get()
или даже::foo::get()
быть в безопасности? Каковы затраты и выгоды от этого?2. В настоящее время я обрабатываю проект с несколькими модулями и исходными файлами. Недавно я понял, что мне следует использовать
::
API для win32, когда я вызываю их внутри модуля, чтобы вызов функций-членов не выглядел как вызов API из глобальной области видимости. Я не предпочитаю вводитьthis->PlayMemberFunc()
текст зановоPlayMemberFunc()
, если нет необходимости устранять путаницу в текущем блоке, где вызывается эта функция-член.
Ответ №1:
Имена в C могут быть квалифицированными и неквалифицированными. Существуют разные правила для поиска квалифицированных и неквалифицированных имен. ::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
. зависит от стиля кодирования. Конечно, как следует из моего примера, могут быть ситуации, когда квалификация является обязательной. Итак, вы могли бы также использовать ::
на всякий случай, если только синтаксис не вызывает у вас отвращения.
Ответ №2:
Поскольку пространств имен в C не существует, не используйте ::HANDLE для доступа к типу ДЕСКРИПТОРА.
Использование добавления :: для глобального пространства имен — хорошая идея для удобства чтения, вы знаете, что тип, к которому вы хотите получить доступ, находится в глобальном пространстве имен.
Более того, если вы находитесь во вложенном пространстве имен и объявляете свой собственный тип ДЕСКРИПТОРА (например), то компилятор будет использовать его вместо windows.h one!
Таким образом, всегда предпочитайте использовать :: перед именами при работе во вложенном пространстве имен.
Ответ №3:
Основной интересный момент заключается в том, каковы различия с точки зрения компилятора, как уже было сказано, если вы включаете ::
, то вы используете квалифицированный поиск, а не неквалифицированный поиск.
Преимущество использования квалифицированного поиска заключается в том, что он всегда сможет точно определить конкретный символ. Недостатком является то, что он всегда будет точно определять этот конкретный символ, т. Е. Он отключит поиск, зависящий от аргумента. ADL — большая и полезная часть языка, и, квалифицируя, вы эффективно отключаете его, и это плохо.
Представьте, что у вас была функция f
в глобальном пространстве имен и что вы добавили тип T
внутри пространства N
имен. Не считайте, что вы хотели добавить перегрузку f
, которая принимала бы a T
в качестве аргумента. Следуя принципу интерфейса, вы можете добавить f
в N
пространство имен, так как f
на самом деле выполняется операция T
, и это относится к типу. В этом случае, если у вас был код, который вызывался (рассмотрим общий код) ::f(obj)
для объекта неизвестного типа U
, компилятор не сможет распознать ::N::f(obj)
потенциальную перегрузку, поскольку код явно запрашивает перегрузку в глобальном пространстве имен.
Использование неквалифицированного поиска дает вам свободу определения функций, которым они принадлежат, вместе с типами, которые используются в качестве аргументов. Хотя это не совсем то же самое, рассмотрите возможность использования swap
, если вы соответствуете std::swap
требованиям, тогда оно не поднимет вашу руку, свернутую void swap( Tamp;, Tamp; )
внутри вашего N
пространства имен…
Я бы полностью определял идентификаторы только тогда, когда компилятор в противном случае не выбрал бы нужный мне элемент.
Ответ №4:
Это в значительной степени вопрос стиля; нет никаких проблем с производительностью или эффективностью, о которых можно говорить. Это может быть хорошей практикой для больших проектов и проектов, предназначенных для компиляции на многих разных платформах, поскольку в этих обстоятельствах более вероятно возникновение коллизий между глобальными именами и именами в пространстве имен.
Ответ №5:
Обычно вам не нужно добавлять ::
дополнение к глобальному пространству имен. (Только в некоторых действительно редких случаях). ИМХО, это вредит удобочитаемости, но, с другой стороны, это, вероятно, не нарушит ваш код
Ответ №6:
Я помещаю весь свой код в пространство имен, и я склонен предпочитать заголовки C заголовкам C, поэтому единственные символы, оставшиеся в глобальном пространстве имен, как правило, принадлежат Windows API. Я избегаю перетаскивания символов из других пространств имен в текущее пространство имен (например, у меня никогда не было using namespace std;
), предпочитая вместо этого явно указывать вещи. Это соответствует руководству Google по стилю C .
Поэтому у меня вошло в привычку квалифицировать вызовы функций WinAPI ::
по нескольким причинам:
-
Согласованность. Для всего, что находится за пределами текущего пространства имен, я ссылаюсь на него явно (например,
std::string
), так почему бы не обратиться к API-интерфейсам Windows явно (например,::LoadLibraryW
)? Пространство имен Windows APIs является глобальным пространством имен. -
Многие функции WinAPI имеют общие имена (например,
DeleteObject
). Если вы не очень хорошо знакомы с кодом, который вы читаете, вы можете не знать, является лиDeleteObject
вызов чем-то в текущем пространстве имен или в Windows API. Таким образом, я нахожу::
разъяснения. -
Многие фреймворки Windows имеют методы с теми же именами, что и исходные вызовы. Например,
ATL::CWindow
имеетGetClientRect
метод с сигнатурой, немного отличающейся от сигнатуры WinAPIGetClientRect
. В этой среде обычно ваш класс является производным отATL::CWindow
, поэтому в реализации вашего класса обычно говорятGetClientRect
, чтобы вызвать унаследованный метод ATL и::GetClientRect
, если вам нужно, вызвать функцию WinAPI. Это не является строго необходимым, поскольку компилятор найдет правильное на основе подписи. Тем не менее, я считаю, что это различие проясняет для читателя.
(Я знаю, что вопрос был на самом деле не о WinAPI, но пример был в терминах WinAPI.)
Комментарии:
1. Интересно прочитать, что кто-то другой следует той же стратегии, что и я; многие Windows API имеют довольно общие имена, поэтому у меня вошло в привычку всегда использовать Windows API с полными именами.
Ответ №7:
Нет, если у вас нет LoadLibrary
метода в вашем классе, вам не нужно использовать глобальную область видимости. На самом деле, вам не следует использовать глобальную область видимости, потому что, если вы позже добавите a LoadLibrary
в свой класс, ваши намерения, вероятно, переопределить глобальную функцию…