Пространства имен (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()<>>
Это называется неименованным или анонимным пространством имен, и это полезно, если вы хотите сделать объявления переменных невидимыми для кода в других файлах (т. е. дать им внутреннюю компоновку), не создавая именованное пространство имен. Весь код, находящийся в том же файле, может видеть идентификаторы в безымянном пространстве имен, но эти идентификаторы, а также само пространство имен, будет невидимым за пределами этого файла или, точнее, вне блока перевода.
namespace
Ключевое слово namespace используется для объявления области действия, которая содержит набор связанных объектов. Пространство имен можно использовать для организации элементов кода и для создания глобально уникальных типов.
namespace SampleNamespace < class SampleClass < >interface ISampleInterface < >struct SampleStruct < >enum SampleEnum < a, b >delegate void SampleDelegate(int i); namespace Nested < class SampleClass2 < >> >
Объявления пространств имен с областью действия файла позволяют объявить, что все типы в файле находятся в одном пространстве имен. Объявления пространств имен с областью действия файла доступны в C# 10. Следующий пример похож на предыдущий, но здесь используется объявление пространства имен с областью действия файла:
using System; namespace SampleFileScopedNamespace; class SampleClass < >interface ISampleInterface < >struct SampleStruct < >enum SampleEnum < a, b >delegate void SampleDelegate(int i);
В предыдущем примере не было вложенного пространства имен. Пространства имен с областью действия файла не могут включать дополнительные объявления пространства имен. Вложенное пространство имен или второе пространство имен с областью действия файла объявить нельзя:
namespace SampleNamespace; class AnotherSampleClass < public void AnotherSampleMethod() < System.Console.WriteLine( "SampleMethod inside SampleNamespace"); >> namespace AnotherNamespace; // Not allowed! namespace ANestedNamespace // Not allowed! < // declarations. >
В пространстве имен можно объявить ноль или больше следующих типов:
- class
- interface
- struct
- enum
- delegate
- вложенные пространства имен можно объявлять везде, кроме объявлений пространств имен с областью действия файла
Компилятор добавляет пространство имен по умолчанию. Это безымянное пространство имен, иногда называемое глобальным пространством имен, существует в каждом файле. Он содержит объявления, не включенные в объявленное пространство имен. Любой идентификатор в глобальном пространстве имен доступен для использования в именованном пространстве имен.
Об этом не говорится прямо, но пространства имен имеют открытый доступ. Описание модификаторов доступа, которые можно назначить элементам в пространстве имен, см. в разделе Модификаторы доступа.
Пространство имен можно определить в двух или нескольких объявлениях. Например, в следующем примере два класса определяются в качестве части пространства имен MyCompany :
namespace MyCompany.Proj1 < class MyClass < >> namespace MyCompany.Proj1 < class MyClass1 < >>
В следующем примере показано, как можно вызвать статический метод вложенного пространства имен.
namespace SomeNameSpace < public class MyClass < static void Main() < Nested.NestedNameSpaceClass.SayHello(); >> // a nested namespace namespace Nested < public class NestedNameSpaceClass < public static void SayHello() < Console.WriteLine("Hello"); >> > > // Output: Hello
Спецификация языка C#
Дополнительные сведения см. в статье Пространства имен в разделе Предварительная спецификация C# 6.0. Дополнительные сведения об объявлениях пространств имен с областью действия файла см. в спецификации функций.
См. также раздел
- Параметры объявления пространства имен (IDE0160 и IDE0161)
- справочник по C#
- Ключевые слова C#
- using
- using static
- Квалификатор псевдонима пространства имен ::
- Пространства имен
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Namespace c что это
Пространство имен позволяет сгруппировать функционал в отдельные контейнеры. Пространство имен представляет блок кода, который содержит набор компонентов (функций, классов и т.д.) и имеет некоторое имя, которое прикрепляется к каждому компоненту из этого пространства имен. Полное имя каждого компонента — это имя пространства имен, за которым следует оператор :: (оператор области видимости или scope operator) и имя компонента. Примером может служить оператор cout , который предназначен для вывода строки на консоль и который определен в пространстве имен std . Соответственно чтобы обратиться к этому оператору, применяется выражение std::cout .
Глобальное пространство имен
Если пространство имен не указано, то по умолчанию применяется глобальное пространство имен . применяется по умолчанию, если пространство имен не было определено. Все имена в глобальном пространстве имен такие же, как вы их объявляете, без прикрепления имени пространства имен. Например:
#include void print(const std::string&); const std::string message; int main() < print(message); >void print(const std::string& text)
Здесь определены функции print и main и константа message и не используется никакого пространства имен. Поэтому фактически функции print и main и константа message определены в глобальном пространстве имен. В принципе для обращения к ним также можно использовать оператор :: , только без названия пространства имен, хотя это и избыточно:
int main()
Стоит отметить, что функция main должна быть определена в глобальном пространстве имен.
Теперь рассмотрим, как определять и использовать свои пространства имен.
Определение пространства имен
Для определения пространства имен применяется ключевое слово namespace , за которым идет название имени пространства имен:
namespace имя_пространства_имен < // код пространства имен >
После имени пространства имен идет блок кода, в который собственно помещаются компоненты пространства имен - функции, классы и т.д.
Например, определим пространство имен, которое назовем hello:
#include namespace hello < const std::string message; void print(const std::string& text) < std::cout > int main() < hello::print(hello::message); // hello work >
Здесь в пространстве hello определена функция print и константа message. И чтобы обратиться к этим компонентам вне пространства имен hello, надо использовать его имя:
hello::print(hello::message);
Внутри пространства имен к его компонентам можно обращаться без имени пространства имен:
namespace hello < const std::string message; void print(const std::string& text) < std::cout void print_default() < std::cout >
Вложенные пространства имен
Одно пространство имен может содержать другие пространства:
#include namespace console < namespace messages < const std::string hello; const std::string welcome; const std::string goodbye; > void print(const std::string& text) < std::cout void print_default() < std::cout > int main()
Здесь в пространстве console определено вложенное пространство messages, которое содержит ряд констант. Для обращения к компонентам вложенного пространства имен также надо использовать его имя:
void print_default()
Вне пространства имен console для обращения к подобным констанстам надо указывать всю цепь пространств имен:
int main() < console::print(console::messages::hello); // console < messages < hello>> >
Директива using
Директива using позволяет ссылаться на любой компонент пространства имен без использования его имени:
#include namespace console < const std::string message; void print(const std::string& text) < std::cout > using namespace console; // подключаем все компоненты пространства console int main() < print(message); // указывать пространство имен не требуется >
Здесь подключаем все компоненты пространства имен console в глобальное пространство имен. И после этого указывать имя этого пространства для обращения к его компонентам не требуется:
using namespace console; // подключаем все компоненты пространства console int main() < print(message); // указывать пространство имен не требуется >
Однако такое подключение может привести к нежелательным последствиям, если в глобальном пространстве имен определяются компоненты с теми же именами (например, переменная message). В этом случае мы можем подключить только отдельные компоненты:
#include namespace console < const std::string message; void print(const std::string& text) < std::cout > using console::print; // подключаем только функцию print int main() < print(console::message); // надо указывать пространство для message >
Здесь подключаем только функцию print:
using console::print;
Поэтому для обращения к ней не надо указывать имя пространства имен. А для обращения к любым другим компонентам надо.
Псевдонимы пространств
Если название пространства длинное, то для него можно определить псевдоним:
namespace псевдоним = название пространства имен;
#include namespace console < namespace messages < const std::string message; > void print(const std::string& text) < std::cout > namespace mes = console::messages; int main() < console::print(mes::message); // обращаемся к message через псевдоним mes >
В данном случае для пространства console::messages устанавливается псевдоним mes .
Библиотеки, пространства имён (namespace) в С++: 8-я часть гайда по языку программирования
Разбираемся, как ускорить работу с кодом в несколько раз, используя готовые решения.



Евгений Кучерявый
Пишет о программировании, в свободное время создаёт игры. Мечтает открыть свою студию и выпускать ламповые RPG.
Это восьмая часть из серии статей «Глубокое погружение в C++». В прошлой статье мы узнали, как хранить данные в массивах. Сегодня — ещё интереснее.
Недавно мы говорили о том, что многие функции уже написаны другими разработчиками и помещены в специальные библиотеки. Если такая библиотека входит в состав языка или находится в открытом доступе, то вы можете использовать все её возможности.
Это очень удобно, и многие специально пишут универсальные библиотеки, которые пригодятся в самых разных проектах. Давайте разберёмся с библиотеками подробнее и научимся создавать свои.
Пространства имён в C++
Пространство имён (англ. namespace) — это группа взаимосвязанных функций, переменных, констант, классов, объектов и других компонентов программы.
С самого начала изучения C++ мы используем команду std: cout, чтобы выводить данные в терминал. На самом деле команда называется просто cout, а std — это пространство имён, в котором она находится.
Пространства имён нужны, чтобы логически связывать части программы. Например, математические функции, физические, бухгалтерские и так далее.
Вот пример создания пространства имён:

Обратите внимание, что функция pow, как и другие математические функции, существует также и в библиотеке cmath.
Заключение
Библиотеки и пространства имён — это полезные инструменты для каждого разработчика. В интернете есть готовые решения для любых задач, поэтому многие работодатели ищут специалистов, которые разбираются в определённой библиотеке.
Если вы часто работаете над однотипными проектами, можете написать для себя библиотеку и подключать её во все проекты, чтобы ускорить работу. Однако новичкам стоит стараться писать код каждый раз заново — так вы сможете его постоянно переосмысливать и замечать то, чего раньше не замечали.
Читайте также:
- Что нужно знать разработчику C++ и какие есть перспективы в карьере
- Apache, Mozilla, Sun и Eclipse: свободные лицензии компаний и некоммерческих организаций
- 5 советов сеньорам: автоматизация, отмазки, потери времени, слово пацана и образование