Что касается глобального пространства имен в C

#c #namespaces #global

#c #пространства имен #глобальное

Вопрос:

В C мы должны добавлять элементы в глобальное пространство имен с :: помощью?

Например, при использовании WinAPI, который находится на C, должен ли я делать ::HANDLE вместо HANDLE и ::LoadLibrary вместо LoadLibrary ? Что говорит об этом C ? Является ли это вообще хорошей идеей, учитывая такие проблемы, как удобочитаемость и удобство обслуживания?

Комментарии:

1. В более общем плане: рекомендуется ли переопределять имена? Например, если я внутри namespace foo { ... } , должен ли я чувствовать себя в безопасности, предполагая, что get() это вызовет my foo::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 :: по нескольким причинам:

  1. Согласованность. Для всего, что находится за пределами текущего пространства имен, я ссылаюсь на него явно (например, std::string ), так почему бы не обратиться к API-интерфейсам Windows явно (например, ::LoadLibraryW )? Пространство имен Windows APIs является глобальным пространством имен.

  2. Многие функции WinAPI имеют общие имена (например, DeleteObject ). Если вы не очень хорошо знакомы с кодом, который вы читаете, вы можете не знать, является ли DeleteObject вызов чем-то в текущем пространстве имен или в Windows API. Таким образом, я нахожу :: разъяснения.

  3. Многие фреймворки Windows имеют методы с теми же именами, что и исходные вызовы. Например, ATL::CWindow имеет GetClientRect метод с сигнатурой, немного отличающейся от сигнатуры WinAPI GetClientRect . В этой среде обычно ваш класс является производным от ATL::CWindow , поэтому в реализации вашего класса обычно говорят GetClientRect , чтобы вызвать унаследованный метод ATL и ::GetClientRect , если вам нужно, вызвать функцию WinAPI. Это не является строго необходимым, поскольку компилятор найдет правильное на основе подписи. Тем не менее, я считаю, что это различие проясняет для читателя.

(Я знаю, что вопрос был на самом деле не о WinAPI, но пример был в терминах WinAPI.)

Комментарии:

1. Интересно прочитать, что кто-то другой следует той же стратегии, что и я; многие Windows API имеют довольно общие имена, поэтому у меня вошло в привычку всегда использовать Windows API с полными именами.

Ответ №7:

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