Перейти к содержимому

Using namespace std c что это

  • автор:

Пространства имен (C++)

Пространство имен — это декларативная область, в рамках которой определяются различные идентификаторы (имена типов, функций, переменных, и т. д.). Пространства имен используются для организации кода в виде логических групп и с целью избежания конфликтов имен, которые могут возникнуть, особенно в таких случаях, когда база кода включает несколько библиотек. Все идентификаторы в пределах пространства имен доступны друг другу без уточнения. Идентификаторы за пределами пространства имен могут получить доступ к членам с помощью полного имени для каждого идентификатора, например, с помощью объявления для одного идентификатора ( using std::string ) или директивы using для всех идентификаторов в пространстве имен ( using namespace std; ). std::vector vec; Код в файлах заголовков всегда должен содержать полное имя в пространстве имен.

В следующем примере показано объявление пространства имен и продемонстрированы три способа доступа к членам пространства имен из кода за его пределами.

namespace ContosoData < class ObjectManager < public: void DoSomething() <>>; void Func(ObjectManager) <> > 

Использование полного имени:

ContosoData::ObjectManager mgr; mgr.DoSomething(); ContosoData::Func(mgr); 

Чтобы добавить в область видимости один идентификатор, используйте объявление using:

using ContosoData::ObjectManager; ObjectManager mgr; mgr.DoSomething(); 

Чтобы добавить в область видимости все идентификаторы пространства имен, используйте директиву using:

using namespace ContosoData; ObjectManager mgr; mgr.DoSomething(); Func(mgr); 

Директивы using

Директива using позволяет использовать все имена в объекте namespace без имени пространства имен в качестве явного квалификатора. Используйте директиву using в файле реализации (т. е. *.cpp), если используется несколько различных идентификаторов в пространстве имен; Если вы используете только один или два идентификатора, рассмотрите возможность использования объявления, чтобы использовать только эти идентификаторы в область, а не все идентификаторы в пространстве имен. Если локальная переменная имеет такое же имя, как и переменная пространства имен, то переменная пространства имен будет скрытой. Создавать переменную пространства имен с те же именем, что и у глобальной переменной, является ошибкой.

Директиву using можно поместить в верхнюю часть CPP-файла (в области видимости файла) или внутрь определения класса или функции.

Без особой необходимости не размещайте директивы using в файлах заголовков (*.h), так как любой файл, содержащий этот заголовок, добавит все идентификаторы пространства имен в область видимости, что может вызвать скрытие или конфликты имен, которые очень трудно отлаживать. В файлах заголовков всегда используйте полные имена. Если эти имена получаются слишком длинными, используйте псевдоним пространства имен для их сокращения. (См. ниже.)

Объявление пространств имен и их членов

Как правило, пространство имен объявляется в файле заголовка. Если реализации функций находятся в отдельном файле, определяйте имена функций полностью, как показано в следующем примере.

// contosoData.h #pragma once namespace ContosoDataServer

Реализации функций в contosodata.cpp должны использовать полное имя, даже если директива using размещается в верхней части файла:

#include "contosodata.h" using namespace ContosoDataServer; void ContosoDataServer::Foo() // use fully-qualified name here < // no qualification needed for Bar() Bar(); >int ContosoDataServer::Bar()

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

Члены именованного пространства имен можно определить вне пространства имен, в котором они объявлены явным определением имени. Однако определение должно располагаться после точки объявления в пространстве имен, окружающем то пространство имен, где находится объявление. Например:

// defining_namespace_members.cpp // C2039 expected namespace V < void f(); >void V::f() < >// ok void V::g() < >// C2039, g() is not yet a member of V namespace V

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

Глобальное пространство имен

Если идентификатор не объявлен явно в пространстве имен, он неявно считается входящим в глобальное пространство имен. Как правило, старайтесь избегать объявления в глобальном область, если это возможно, за исключением основной функции точки входа, которая должна находиться в глобальном пространстве имен. Чтобы явно указать глобальный идентификатор, используйте оператор разрешения области видимости без имени, как сделано в ::SomeFunction(x); . Это позволит отличать данный идентификатор от любого другого элемента с таким же именем, находящегося в другом пространстве имен. Кроме того, это облегчит понимание кода.

Пространство имен std

Все стандартные типы и функции библиотек C++ объявляются в std пространстве имен или пространствах имен, вложенных внутри std .

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

Пространства имен могут быть вложенными. Обычное вложенное пространство имен имеет неквалифицированный доступ к членам родительского элемента, но родительские члены не имеют неквалифицированного доступа к вложенному пространству имен (если он не объявлен как встроенный), как показано в следующем примере:

namespace ContosoDataServer < void Foo(); namespace Details < int CountImpl; void Ban() < return Foo(); >> int Bar(); int Baz(int i) < return Details::CountImpl; >> 

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

Встроенные пространства имен (C++11)

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

// Header.h #include namespace Test < namespace old_ns < std::string Func() < return std::string("Hello from old"); >> inline namespace new_ns < std::string Func() < return std::string("Hello from new"); >> > // main.cpp #include "header.h" #include #include int main() < using namespace Test; using namespace std; string s = Func(); std::cout 

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

namespace Parent < inline namespace new_ns < template struct C < T member; >; > template<> class C <>; > 

Встроенные пространства имен можно использовать как механизм управления версиями для управления изменениями в открытом интерфейсе библиотеки. Например, можно создать одно родительское пространство имен и инкапсулировать каждую версию интерфейса в своем собственном пространстве имен, вложенном в родительское. Пространство имен, которое содержит самую последнюю или основную версию, квалифицируется как встроенное и поэтому представляется так, будто оно является непосредственным членом родительского пространства имен. Клиентский код, вызывающий Parent::Class, автоматически привязывается к новому коду. Клиенты, которые предпочитают использовать старую версию, могут по-прежнему получить доступ к ней, используя полный путь к вложенному пространству имен, содержащему данный код.

Ключевое слово inline должно применяться к первому объявлению пространства имен в единице компиляции.

В следующем примере показано две версии интерфейса: каждое — во вложенном пространстве имен. Пространство имен v_20 содержит некоторые изменения из интерфейса v_10 и помечается как встроенное. Клиентский код, который использует новую библиотеку и вызывает Contoso::Funcs::Add , вызовет версию v_20. Код, который пытается вызвать Contoso::Funcs::Divide , теперь будет вызывать ошибку времени компиляции. Если действительно требуется эта функция, доступ к версии v_10 можно получить путем явного вызова Contoso::v_10::Funcs::Divide .

namespace Contoso < namespace v_10 < template class Funcs < public: Funcs(void); T Add(T a, T b); T Subtract(T a, T b); T Multiply(T a, T b); T Divide(T a, T b); >; > inline namespace v_20 < template class Funcs < public: Funcs(void); T Add(T a, T b); T Subtract(T a, T b); T Multiply(T a, T b); std::vectorLog(double); T Accumulate(std::vector nums); >; > > 

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

Имена пространств имен должны быть уникальными, из-за чего зачастую они получаются не слишком короткими. Если длина имени затрудняет чтение кода или утомительно вводить в файл заголовка, где нельзя использовать директивы, можно сделать псевдоним пространства имен, который служит сокращенным для фактического имени. Например:

namespace a_very_long_namespace_name < class Foo <>; > namespace AVLNN = a_very_long_namespace_name; void Bar(AVLNN::Foo foo)

анонимные или безымянные пространства имен

Вы можете создать явное пространство имен, но не присвоить ему имя.

namespace < int MyFunc()<>> 

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

Пространство имен (using namespace std;)

Очень часто в интернете вижу как многие программисты усердно пишут везде программы используя в коде std:: . Зачем они это делают? Почему нельзя просто использовать using namespace std; перед программой, так же удобнее и код начинает "дышать". Или это плохой тон и стоит переучиваться на использование std:: непосредственно в коде программы?

Отслеживать
31k 13 13 золотых знаков 96 96 серебряных знаков 157 157 бронзовых знаков
задан 11 апр 2015 в 14:23
347 1 1 золотой знак 3 3 серебряных знака 6 6 бронзовых знаков

Добро пожаловать в мир крестов. Я не знаю как ответить на этот вопрос. По поводу дышашего кода из за одного using объявления вы преувеличиваете.

11 апр 2015 в 14:24

Так почему же преувеличиваю? Грубо говоря что я потратил всего одну строчку для using namespace std; и что у меня во всём коде можно сказать на каждой строчке красуется std. По факту очень даже ощутимая разница если визуально оценивать код. Может это конечно глупости и не стоит по поводу этого заморачиваться. Но пока что, этот момент мне не понятен)

11 апр 2015 в 14:28

Вы понимаете что в C например вообще нет пространств имен? А в С++11 директива using может быть использована например для создания шаблонных синонимов или вместо typedef для создания синонима типа. Короче я не знаю как ответить на вопрос почему какие-то люди где-то там далеко вместо using namepace std; пишут std::cout . Может им так нравится или они просто дураки? Откуда мне знать точную причину?

11 апр 2015 в 14:40
Вот ещё по теме: ru.stackoverflow.com/q/201310/10105
11 апр 2015 в 16:03
А что такое "дышащий код"?
26 апр 2015 в 6:31

5 ответов 5

Сортировка: Сброс на вариант по умолчанию

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

Явное указание пространства имён — это избавление от потенциальных проблем в будущем. Положим, вы подключили через using namespace два пространства имён. Всё замечательно, кратко, красиво.

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

В лучшем случае ваш код не соберётся. Может упасть. А может так получиться, что ваш код перестанет работать у клиента в 1% случаев. Всё может быть.

Отлавливать и исправлять подобные проблемы мучительно больно.

Насколько это важно конкретно для вас — решать вам. Если у вас простой проектик и от силы пара сторонних библиотек (или вообще только стандартная библиотека), то можно не заморачиваться с явным указанием пространств имён. Если проект огромный, с десятками библиотек, то может оказаться более удобным (и наглядным) всегда указывать пространства имён.

Банальный пример: положим, вы пользуетесь только стандартной библиотекой и boost, поэтому решили везде писать:

using namespace std; using namespace boost; 

. а теперь выходит новая версия стандартной библиотеки, в которой из boost перетащено много классов. И внезапно ваш код больше не компилируется.

В других языках другие традиции. Например, в C# почти всегда пишут краткие имена классов, и только в случае конфликтов явно указывают пространство имён или используют алиасы. Язык немного отличается: там нет функций вне классов. Это позволяет меньше терять читаемость и реже натыкаться на неожиданные конфликты.

Библиотеки, пространства имён (namespace) в С++: 8-я часть гайда по языку программирования

Разбираемся, как ускорить работу с кодом в несколько раз, используя готовые решения.

Евгений Кучерявый

Евгений Кучерявый

Пишет о программировании, в свободное время создаёт игры. Мечтает открыть свою студию и выпускать ламповые RPG.

Это восьмая часть из серии статей «Глубокое погружение в C++». В прошлой статье мы узнали, как хранить данные в массивах. Сегодня — ещё интереснее.

Недавно мы говорили о том, что многие функции уже написаны другими разработчиками и помещены в специальные библиотеки. Если такая библиотека входит в состав языка или находится в открытом доступе, то вы можете использовать все её возможности.

Это очень удобно, и многие специально пишут универсальные библиотеки, которые пригодятся в самых разных проектах. Давайте разберёмся с библиотеками подробнее и научимся создавать свои.

Пространства имён в C++

Пространство имён (англ. namespace) — это группа взаимосвязанных функций, переменных, констант, классов, объектов и других компонентов программы.

С самого начала изучения C++ мы используем команду std: cout, чтобы выводить данные в терминал. На самом деле команда называется просто cout, а std — это пространство имён, в котором она находится.

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

Вот пример создания пространства имён:

Обратите внимание, что функция pow, как и другие математические функции, существует также и в библиотеке cmath.

Заключение

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

Если вы часто работаете над однотипными проектами, можете написать для себя библиотеку и подключать её во все проекты, чтобы ускорить работу. Однако новичкам стоит стараться писать код каждый раз заново — так вы сможете его постоянно переосмысливать и замечать то, чего раньше не замечали.

Читайте также:

  • Что нужно знать разработчику C++ и какие есть перспективы в карьере
  • Apache, Mozilla, Sun и Eclipse: свободные лицензии компаний и некоммерческих организаций
  • 5 советов сеньорам: автоматизация, отмазки, потери времени, слово пацана и образование

Урок №54. using-стейтменты

Если вы часто используете Стандартную библиотеку C++, то постоянное добавление std:: к используемым объектам может быть несколько утомительным, не правда ли? Язык C++ предоставляет альтернативы в виде using-стейтментов.

Оглавление:

  1. Использование «using-объявления»
  2. Использование «using-директивы»
  3. Пример конфликта c «using-директивой»
  4. Область видимости «using-объявления» и «using-директивы»
  5. Отмена/замена using-стейтментов

Использование «using-объявления»

Одной из альтернатив является использование «using-объявления». Вот программа «Hello, world!» с «using-объявлением» в строке №5:

using std :: cout ; // "using-объявление" сообщает компилятору, что cout следует обрабатывать, как std::cout

cout << "Hello, world!" ; // и никакого префикса std:: уже здесь не нужно!

Строка using std::cout; сообщает компилятору, что мы будем использовать объект cout из пространства имен std. И каждый раз, когда компилятор будет сталкиваться с cout , он будет понимать, что это std::cout .

Конечно, в этом случае мы не сэкономили много усилий, но в программе, где объекты из пространства имен std используются сотни, если не тысячи раз, «using-объявление» неплохо так экономит время, усилия и улучшает читабельность кода. Также для каждого объекта нужно использовать отдельное «using-объявление» (например, отдельное для std::cout , отдельное для std::cin и отдельное для std::endl ).

Хотя этот способ является менее предпочтительным, чем использование префикса std:: , он все же является абсолютно безопасным и приемлемым.

Использование «using-директивы»

Второй альтернативой является использование «using-директивы». Вот программа «Hello, world!» с «using-директивой» в строке №5:

using namespace std ; // "using-директива" сообщает компилятору, что мы используем все объекты из пространства имен std!

cout << "Hello, world!" ; // так что никакого префикса std:: здесь уже не нужно!

Много разработчиков спорят насчет использования «using-директивы». Так как с её помощью мы подключаем ВСЕ имена из пространства имен std, то вероятность возникновения конфликтов имен значительно возрастает (но все же эта вероятность в глобальном масштабе остается незначительной). using namespace std; сообщает компилятору, что мы хотим использовать всё, что находится в пространстве имен std, так что, если компилятор найдет имя, которое не сможет распознать, он будет проверять его наличие в пространстве имен std.

Совет: Старайтесь избегать использования «using-директивы» (насколько это возможно).

Пример конфликта c «using-директивой»

Рассмотрим пример, где использование «using-директивы» создает неопределенность:

int cout ( ) // объявляем нашу собственную функцию "cout"
using namespace std ; // делаем std::cout доступным по "cout"

cout

Здесь компилятор не сможет понять, использовать ли ему std::cout или функцию cout(), которую мы определили сами. В результате, получим ошибку неоднозначности. Хоть это и банальный пример, но если бы мы добавили префикс std:: к cout:

std :: cout << "Hello, world!" ; // сообщаем компилятору, что хотим использовать std::cout

Или использовали бы «using-объявление» вместо «using-директивы»:

using std :: cout ; // сообщаем компилятору, что cout означает std::cout
cout << "Hello, world!" ; // так что здесь следует использовать std::cout

Тогда наша программа была бы без ошибок.

Большинство программистов избегают использования «using-директивы» именно по этой причине. Другие считают это приемлемым до тех пор, пока «using-директива» используется только в пределах отдельных функций (что значительно сокращает масштабы возникновения конфликтов имен).

Области видимости «using-объявления» и «using-директивы»

Если «using-объявление» или «using-директива» используются в блоке, то они применяются только внутри этого блока (по обычным правилам локальной области видимости). Это хорошо, поскольку уменьшает масштабы возникновения конфликтов имен до отдельных блоков. Однако многие начинающие программисты пишут «using-директиву» в глобальной области видимости (вне функции main() или вообще вне любых функций). Этим они вытаскивают все имена из пространства имен std напрямую в глобальную область видимости, значительно увеличивая вероятность возникновения конфликтов имен. А это уже не хорошо.

Правило: Никогда не используйте using-стейтменты вне тела функций.

Отмена/замена using-стейтментов

Как только один using-стейтмент был объявлен, его невозможно отменить или заменить другим using-стейтментом в пределах области видимости, в которой он был объявлен. Например:

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

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