Пространство имен std c что это
Пространства имен (namespaces) в C++
Пространство имен в C ++ — это обобщенная область видимости. Его объявление начинается с зарезервированного слова namespace, за которым следует имя по выбору программиста, а затем блок в фигурных скобках. Блок содержит базовые объявления и / или определения объектов, функций и других сущностей C ++.
Рассмотрим следующие два скалярных оператора в глобальной области в следующей программе:
int varId = 5 ;
float varId = 2.3 ;
Попытка скомпилировать эту программу приводит к ошибке компиляции. Есть две переменные с одинаковым именем varId. Хотя это две разные переменные двух разных типов, int и float, компилятор отклоняет два объявления, потому что они имеют одно и то же имя. Следующая программа решает эту проблему, объявляя переменные с одинаковыми именами в двух разных обобщенных областях:
namespace NA
<
int varId = 5 ;
>
namespace NB
<
float varId = 2.3 ;
>
int main ( )
<
cout NA :: varId ‘ \n ‘ ;
cout NB :: varId ‘ \n ‘ ;
Результат выглядит следующим образом:
В этой статье рассматривается основная концепция пространства имен и его использование в языке программирования C ++. Чтобы следовать этой статье, вы должны иметь базовые знания языка C ++. Вы также должны знать область действия C ++, хотя она кратко объясняется в этой статье. Чтобы узнать больше о области действия C ++, найдите фразу «Область действия в C ++» (без кавычек) в поле поиска любой веб-страницы linuxhint.com и нажмите Enter. Это приведет вас к статье, написанной этим автором.
Что такое пространство имен?
Декларативная область — это самая большая часть программы, в которой допустимо имя объекта (переменной). Эта область называется областью действия. Пространство имен в C ++ — это обобщенная область видимости, основной целью которой является разрешение конфликтов имен. Пространство имен имеет базовые объявления и / или определения сущностей.
Глобальное пространство имен и его проблема
Глобальное пространство имен — это глобальная область видимости. Рассмотрим следующую короткую программу:
int ident = 55 ;
float ident = 12.17 ;
В приведенной выше программе есть две переменные, обе называемые идентификатором. Эти переменные находятся в глобальной области видимости; то есть они находятся в глобальном пространстве имен. Попытка скомпилировать эту программу завершится ошибкой. Глобальная область видимости не принимает более одной переменной с одинаковым именем, поэтому существует необходимость в настраиваемом пространстве имен.
Пользовательское пространство имен
namespace NA
<
int varInt = 6 ;
float flt ;
>
namespace NB
<
int varInt = 7 ;
float flt ;
>
int main ( )
<
cout NA :: varInt ‘ \n ‘ ;
cout NB :: varInt ‘ \n ‘ ;
NA :: flt = 2.5 ;
NB :: flt = 4.8 ;
cout NA :: flt ‘ \n ‘ ;
cout NB :: flt ‘ \n ‘ ;
Обратите внимание, что имена NA :: flt и NB :: flt в конечном итоге определены в функции main (). C ++ не допускает такого определения в глобальной области видимости.
Обратите внимание, что настраиваемое пространство имен является вложенным пространством имен для глобального пространства имен.
Директива использования
Чтобы не вводить все время «namepace :: name» вместо просто «name» после объявления пространства имен, вы можете использовать директиву using. Синтаксис использования директивы using следующий:
С помощью директивы не директива препроцессора, поэтому она заканчивается точкой с запятой (;).
Следующая программа иллюстрирует использование директивы using и др.:
namespace NB
<
int varInt = 7 ;
int func ( )
<
return varInt ;
>
>
int fn ( )
<
using namespace NB ;
int myVar2 = func ( ) ;
//other objects and functions from NB follow.
return myVar2 ;
>
int myVar3 = NB :: func ( ) ;
int main ( )
<
cout fn ( ) ‘ ‘ myVar3 ‘ \n ‘ ;
Переменная, объявленная в глобальной области (глобальном пространстве имен), просматривается от точки объявления до конца файла. Это также видно во вложенных пространствах имен (вложенных областях), таких как вложенная область видимости функции fn () выше. С помощью директивы соединяет его пространство имен из позиции, в которой он размещен в конце области, в которой он размещен.
Имя func () из пространства имен NB нельзя увидеть под определением fn (), потому что » using namespace NB;» был помещен в область действия функции (блок). При этом условии, чтобы использовать функцию » func () » вне блока (области) пространства имен NB, ему должен предшествовать » NB :: «, как в следующем операторе:
С помощью директивы присоединяется своим пространством имен с внешним гнездовым пространством именами из положения, в котором он находится на конец внешних вложенности имен. В следующей программе пространство имен NA объединено с глобальным пространством имен. Оба пространства имен затем расширяются в пространство имен определения функции fn (), в котором они объединяются с пространством имен NB. Пространство имен NB заканчивается в конце определения функции fn (), а два предыдущих пространства имен продолжаются до конца файла (считывания кода).
namespace NA
<
int varInt = 6 ;
int func ( )
<
return varInt ;
>
namespace NB
<
int varInt = 7 ;
int func ( )
<
return varInt ;
>
>
using namespace NA ;
int myVar0 = varInt ;
//other objects and functions from :: and NB follow.
int fn ( )
<
int myVar1 = varInt ;
using namespace NB ;
int myVar2 = NB :: func ( ) ;
//other objects and functions from NB follow, till end of this scope.
return myVar1 + myVar2 ;
>
//Only objects and functions from :: and NB follow.
int myVar3 = NB :: func ( ) ;
int main ( )
<
cout myVar0 ‘ ‘ fn ( ) ‘ ‘ myVar3 ‘ \n ‘ ;
На выходе будет 6, 13, 7.
Под утверждением » using namespace NA; «Переменные из глобального пространства имен и пространства имен NA могут использоваться без указания их исходного пространства имен. Следующий оператор использует varInt пространства имен NA. Область объединенного пространства имен global и NA простирается в пространство имен функции fn (). Итак, varInt первого оператора в области видимости функции fn () относится к пространству имен NA.
Поскольку область для глобального пространства имен и пространства имен NA распространяется на всю область видимости fn (), после » int myVar2 = NB :: func ();, «Любое имя из пространства имен NB может использоваться только в области fn () без предшествующего ему» NB :: «, только если оно не встречается в NA и глобальных пространствах имен (блоках). В противном случае ему должно предшествовать » NB :: «. Область объединенных пространств имен для NA и global продолжается ниже определения fn () и в функцию main () до конца файла.
Расширение пространства имен NB начинается с » int myVar2 = NB :: func (); «В блоке fn () и заканчивается в конце блока определения fn ().
Примечание: Пространства имен, регионы которых соединяются, не должны иметь одинаковые имена переменных в разных блоках пространств имен, так как это все равно вызовет конфликт.
Области пространства имен
Пространство имен — это область видимости. Помимо глобального пространства имен (глобальная область видимости), любое пространство имен должно быть объявлено в блоке. Этот блок является первой частью возможных распределенных областей пространства имен. С помощью директивы using пространство имен может быть расширено как регионы в других областях.
Объекты, объявленные в теле пространства имен, называются членами этого пространства имен, а имена, введенные этими объявлениями в декларативную область пространства имен, называются именами членов этого пространства имен.
Вложенные пространства имен
Следующая программа показывает вложенные пространства имен:
namespace A
<
int i = 1 ;
namespace B
<
int i = 2 ;
namespace C
<
int i = 3 ;
>
>
>
int main ( )
<
cout A :: i ‘ ‘ A :: B :: i ‘ ‘ A :: B :: C :: i ‘ \n ‘ ;
Обратите внимание, что доступ к трем значениям был осуществлен с помощью оператора разрешения области видимости.
Стандартное пространство имен
В C ++ есть библиотека, называемая стандартной библиотекой. Имена объектов, функций и других сущностей в этой библиотеке взяты из пространства имен, называемого стандартным пространством имен, записанного как std. Стандартная библиотека содержит подбиблиотеки, и одна из этих подбиблиотек — iostream. Библиотека iostream содержит объект cout, который используется для отправки результатов на консоль (терминал).
Имя cout должно находиться в пространстве имен std. Чтобы использовать iostream с его пространством имен std, программа должна быть следующей:
Обратите внимание на использование директивы using и std. Термин » #include » является директивой препроцессора и не заканчивается точкой с запятой. Он включает в себя «файл» iostream в позиции своей директивы.
Заключение
Пространство имен — это область видимости. Описание (определение) пространства имен содержит базовые объявления и / или определения объектов, функций и других сущностей C ++. Вне определения пространства имен доступ к имени можно получить с помощью синтаксиса » namespaceName :: name «. Помимо глобального пространства имен (глобальная область видимости), любое пространство имен должно быть объявлено в блоке. Этот блок является первой частью возможных распределенных областей пространства имен. С помощью директивы using пространство имен может быть расширено как регионы в других областях. Пространства имен, регионы которых соединяются, не должны иметь одинаковые имена переменных в разных блоках пространств имен, так как это все равно вызовет конфликт имен.
Почему с ‘using namespace std;’ в *.cpp-файлах может быть очень плохо
То, что написано ниже, для многих квалифицированных C++ разработчиков будет прекрасно известным и очевидным, но тем не менее, я периодически встречаю using namespace std; в коде различных проектов, а недавно в нашумевшей статье про впечатления от высшего образования было упомянуто, что студентов так учат писать код в вузах, что и сподвигло меня написать эту заметку.
Для чего вообще придумали пространства имен в C++? Когда какие-то две сущности (типы, функции, и т.д.) имеют идентификаторы, которые могут конфликтовать друг с другом при совместном использовании, C++ позволяет объявлять пространства с помощью ключевого слова namespace. Всё, что объявлено внутри пространства имен, принадлежит только этому пространству имен (а не глобальному). Используя using мы вытаскиваем сущности какого-либо пространства имен в глобальный контекст.
А теперь посмотрим, к чему это может привести.
Допустим, вы используете две библиотеки под названием Foo и Bar и написали в начале файла что-то типа
. таким образом вытащив всё, что есть в foo:: и в bar:: в глобальное пространство имен.
Все работает нормально, и вы можете без проблем вызвать Blah() из Foo и Quux() из Bar. Но однажды вы обновляете библиотеку Foo до новой версии Foo 2.0, которая теперь еще имеет в себе функцию Quux().
Теперь у вас конфликт: и Foo 2.0, и Bar импортируют Quux() в ваше глобальное пространство имен. В лучшем случае это вызовет ошибку на этапе компиляции, и исправление этого потребует усилий и времени.
А вот если бы вы явно указывали в коде метод с его пространством имен, а именно, foo::Blah() и bar::Quux(), то добавление foo::Quux() не было бы проблемой.
Но всё может быть даже хуже!
В библиотеку Foo 2.0 могла быть добавлена функция foo::Quux(), про которую компилятор по ряду причин посчитает, что она однозначно лучше подходит для некоторых ваших вызовов Quux(), чем bar::Quux(), вызывавшаяся в вашем коде на протяжении многих лет. Тогда ваш код все равно скомпилируется, но будет молча вызывать неправильную функцию и делать бог весть что. И это может привести к куче неожиданных и сложноотлаживающихся ошибок.
Имейте в виду, что пространство имен std:: имеет множество идентификаторов, многие из которых являются очень распространенными (list, sort, string, iterator, swap), которые, скорее всего, могут появиться и в другом коде, либо наоборот, в следущей версии стандарта C++ в std добавят что-то, что совпадет с каким-то из идентификаторов в вашем существующем коде.
Если вы считаете это маловероятным, то посмотрим на реальные примеры со stackoverflow:
Вот тут был задан вопрос о том, почему код возвращает совершенно не те результаты, что от него ожидает разработчик. По факту там происходит именно описанное выше: разработчик передает в функцию аргументы неправильного типа, но это не вызывает ошибку компиляции, а компилятор просто молча использует вместо объявленной выше функции distance() библиотечную функцию std::distance() из std:: ставшего глобальным неймспейсом.
Второй пример на ту же тему: вместо функции swap() используется std::swap(). Опять же, никакой ошибки компиляции, а просто неправильный результат работы.
Так что подобное происходит гораздо чаще, чем кажется.
Using namespace std что это такое и как используется в Visual C++
Отвечая на вопрос, что такое using namespace std для началае следует отметить, что переводе с английского описываемый термин означает пространство имени, являющиеся областью декларации, необходимо для определения различных идентификационных форм: функций и зависимых/независимых переменных.
Благодаря ей не происходит конфликта между именами, поскольку случаются ситуации, когда несколько переменных принимают одинаковые значения. Как правило, это происходит в том случае, когда созданы разные библиотеки.
Идентификаторы находятся в свободном доступе по отношению друг к другу. Они получают свободный доступ к независимым членам при эксплуатации полного именного формата.
Для этого крайне важно, чтобы объект содержал полную форму наименования using namespace std. Это важно, чтобы визуально понять, каким образом выглядит объявление, располагаясь в имени пространства.
Содержание:
На изображении представлено несколько вариаций доступа к кодировкам, располагающихся в пределах и за его ограждениями:
Директива Using
Using директива разрешает эксплуатацию всех имеющихся имен, которые включены в пространство имени.
При этом указывать квалификатор нет необходимости.
В том случае, когда существует только пару имен, актуальным будет создание обыкновенного имени.
Тогда можно добавить только необходимые идентификаторы, а остальные не трогать.
Важно отметить, что если наименование локальной переменной с основной будут совпадать, то в таком случае первая будет находится в скрытом доступе.
Стоит принять во внимание, что создание переменных с одинаковым наименованием является недопустимым действием.
Совет! Для удобства использования, using директива может быть расположена в верхушке файла формата cpp., либо наоборот, помещается внутрь созданной библиотеки.
Чтобы обеспечить для себя максимально комфортные условия работы, можно поработать над размещением необходимых файлов.
Если нет крайней необходимости, то директиву using не стоит размещать в заголовках файлом формата H.
Это связано с тем, что при данном действии все идентификаторы станут активными в поле видимости, повышая вероятность возникновения конфликтности некоторых наименований.
Для файлов оптимальным решением станет использование полного наименования.
В том случае, когда они получаются чересчур длинными, можно использовать сокращение в виде псевдонимов.
Читайте также:
Объявления в именном пространстве
Принято размещать объявления в виде названий файлов. В том случае, когда исполнение заданных функций размещено в отдельной библиотеке или файле, важно определить полное наименование.
Чтобы понимать, о каких действиях идет речь, стоит ознакомиться со следующим изображением:
Чтобы реализовать функцию contosodata формата cpp., также важно использовать полное наименование и в том случае, когда директива стоит в самом начале:
Using namespace std. может содержать объявления сразу в нескольких разделах, находящихся в одном и том же файле.
За счет компилятора происходит объединение всех элементов, пока происходит обработка данных.
Далее пространство будет включать все доступные имена и члены, которые были заявлены во всех разделах.
Так, например, std., как правило, объявляется во всех заголовках доступных файлов, располагающихся в доступных библиотеках стандартного типа.
Что касается определения, то оно должно быть после объявления в пространстве имени, где оно создано.
В качестве наглядного примера обращаем внимание на следующее изображение:
Чаще всего такая ошибка появляется в том случае, когда нарушается порядок определения, либо составляющие части полного наименования включены сразу в доступных объектах.
Когда идентификационные файлы не заявляется в определенном именном пространстве, он формально входит в пространство глобального типа.
Совет! Если нет острой необходимости, то рекомендуется избегать включения членов в пространство глобального типа.
Существенным исключением из правил может быть только главная (main) опция, подразумевающая обязательное включение в обширном пространстве.
Чтобы создать идентификатор глобального типа, необходимо задействовать соответствующий функционала видимости, ввиде полного наименования.
Подобное действие поможет создать отличительное свойство одного идентификатора от других имеющихся, которые находятся в другом именном пространстве.
6.2 – Пользовательские пространства имен
В уроке «2.8 – Конфликты имен и пространства имен» мы познакомились с концепциями конфликтов имен и пространств имен. Напоминаем, что конфликт имен возникает, когда два идентичных идентификатора вводятся в одну и ту же область видимости, и компилятор не может однозначно определить, какой из них использовать. Когда это происходит, компилятор или компоновщик выдаст ошибку, потому что у них недостаточно информации для разрешения неоднозначности. По мере того, как программы становятся больше, количество идентификаторов увеличивается линейно, что, в свою очередь, приводит к экспоненциальному увеличению вероятности возникновения конфликта имен.
Давайте еще раз рассмотрим пример конфликта имен, а затем покажем, как мы можем разрешить его с помощью пространств имен. В следующем примере foo.cpp и goo.cpp – это исходные файлы, содержащие функции, выполняющие разные действия, но имеющие одинаковое имя и параметры.
Определение ваших собственных пространств имен
Идентификаторы пространства имен обычно пишутся без заглавных букв.
Ниже приведен пример файлов из предыдущего примера, переписанных с использованием пространств имен:
А ответ – теперь мы получаем еще одну ошибку!
В этом случае компилятор был удовлетворен (нашим предварительным объявлением), но компоновщик не смог найти определение для doSomething в глобальном пространстве имен. Это потому, что обе наши версии doSomething больше не находятся в глобальном пространстве имен!
Есть два разных способа сообщить компилятору, какую версию doSomething() использовать, с помощью оператора разрешения области видимости или с помощью инструкций using (которые мы обсудим на следующем уроке этой главы).
Для удобства чтения в последующих примерах мы объединим предыдущие примеры в однофайловый проект.
Доступ к пространству имен с помощью оператора разрешения области видимости ( :: )
Лучший способ указать компилятору искать идентификатор в определенном пространстве имен – это использовать оператор разрешения области видимости ( :: ). Оператор разрешения области видимости сообщает компилятору, что идентификатор, указанный правым операндом, следует искать в области видимости левого операнда.
Это дает ожидаемый результат:
Эта программа дает следующий результат:
Оператор разрешения области видимости хорош, потому что он позволяет нам явно выбирать, в каком пространстве имен мы хотим искать, и поэтому нет потенциальной неоднозначности. Мы даже можем сделать следующее:
Эта программа дает следующий результат:
Использование оператора разрешения области видимости без префикса имени
Оператор разрешения области видимости также может использоваться перед идентификатором без указания имени пространства имен (например, ::doSomething ). В таком случае идентификатор (например, doSomething ) ищется в глобальном пространстве имен.
В приведенном выше примере ::print() работает так же, как если бы мы вызвали print() без разрешения области видимости, поэтому использование оператора разрешения области видимости в этом случае излишне. Но в следующем примере будет показан случай, когда оператор разрешения области видимости без указания пространства имен может быть полезен.
Разрешение идентификатора из пространства имен
Если идентификатор используется внутри пространства имен, и разрешение области видимости не предусмотрено, компилятор сначала попытается найти соответствующее объявление в том же пространстве имен. Если соответствующий идентификатор не найден, компилятор затем последовательно проверяет каждое содержащее его пространство имен, чтобы увидеть, найдено ли совпадение, причем глобальное пространство имен проверяется последним.
Эта программа напечатает:
Если бы foo::print() не была найден, компилятор проверил бы содержащее его пространство имен (в данном случае глобальное пространство имен), чтобы увидеть, можно ли найти print() там.
Допускается несколько блоков пространства имен
Допускается объявлять блоки пространства имен в нескольких местах (либо в нескольких файлах, либо в нескольких местах в одном файле). Все объявления в пространстве имен считаются частью одного пространства имен.
Это работает именно так, как вы ожидаете:
Предупреждение
Когда вы разделяете свой код на несколько файлов, вам нужно будет использовать пространство имен в заголовочном и исходном файлах.
Вложенные пространства имен
Пространства имен могут быть вложены в другие пространства имен. Например:
Начиная с C++17, вложенные пространства имен также могут быть объявлены следующим образом:
Псевдонимы пространств имен
Поскольку ввод полного имени переменной или функции во вложенном пространстве имен может быть болезненным, C++ позволяет создавать псевдонимы пространств имен, которые позволяют нам временно сократить длинную последовательность пространств имен до чего-то более короткого:
Стоит отметить, что пространства имен в C++ изначально были разработаны не как способ реализации информационной иерархии – они были разработаны, в первую очередь, как механизм предотвращения конфликтов имен. В качестве доказательства этого обратите внимание, что вся стандартная библиотека находится в одном пространстве имен std:: (с некоторыми вложенными пространствами имен, используемыми для новых функций библиотеки). Некоторые новые языки (например, C#) в этом отношении отличаются от C++.
В общем, вам следует избегать глубоких вложений пространств имен.
Когда следует использовать пространства имен
В приложениях пространства имен могут использоваться для отделения кода, специфичного для приложения, от кода, который может быть повторно использован позже (например, математические функции). Например, физические и математические функции могут входить в одно пространство имен (например, math:: ). Функции языка и локализации – в другое пространство имен (например, lang:: ).
Когда вы пишете библиотеку или код, который хотите распространить среди других, всегда помещайте свой код в пространство имен. Код, в котором используется ваша библиотека, может не соответствовать лучшим практикам – в таком случае, если объявления вашей библиотеки не находятся в пространстве имен, существует высокая вероятность возникновения конфликтов имен. В качестве дополнительного преимущества, размещение кода библиотеки внутри пространства имен также позволяет пользователю видеть содержимое вашей библиотеки с помощью функции автодополнения и предложений редактора кода.