Ескерім
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Пространство имен — это декларативная область, в рамках которой определяются различные идентификаторы (имена типов, функций, переменных, и т. д.). Пространства имен используются для организации кода в виде логических групп и с целью избежания конфликтов имен, которые могут возникнуть, особенно в таких случаях, когда база кода включает несколько библиотек. Все идентификаторы в пределах пространства имен доступны друг другу без уточнения. Идентификаторы за пределами пространства имен могут получить доступ к членам с помощью полного имени для каждого идентификатора, например, с помощью объявления для одного идентификатора (using std::string
) или директивы using для всех идентификаторов в пространстве имен (using namespace std;
).std::vector<std::string> 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
{
void Foo();
int Bar();
}
Реализации функций в 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(){return 0;}
Пространство имен может быть объявлено в нескольких блоках в одном файле и в нескольких файлах. Компилятор соединит вместе все части во время предварительной обработки и полученное в результате пространство имен будет содержать все члены, объявленные во всех частях. Примером этого является пространство имен 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 {
void g();
}
Эта ошибка может возникнуть, когда члены пространства имен объявляются в нескольких файлах заголовка и эти заголовки не включены в правильном порядке.
Глобальное пространство имен
Если идентификатор не объявлен явно в пространстве имен, он неявно считается входящим в глобальное пространство имен. Как правило, старайтесь избегать объявления в глобальной области, если это возможно, за исключением основной функции точки входа, которая должна находиться в глобальном пространстве имен. Чтобы явно указать глобальный идентификатор, используйте оператор разрешения области видимости без имени, как сделано в ::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 <string>
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 <string>
#include <iostream>
int main()
{
using namespace Test;
using namespace std;
string s = Func();
std::cout << s << std::endl; // "Hello from new"
return 0;
}
В следующем примере показано, как можно объявить специализацию в родительском пространстве имен шаблона, объявленного во встроенном пространстве имен.
namespace Parent
{
inline namespace new_ns
{
template <typename T>
struct C
{
T member;
};
}
template<>
class C<int> {};
}
Встроенные пространства имен можно использовать как механизм управления версиями для управления изменениями в открытом интерфейсе библиотеки. Например, можно создать одно родительское пространство имен и инкапсулировать каждую версию интерфейса в своем собственном пространстве имен, вложенном в родительское. Пространство имен, которое содержит самую последнюю или основную версию, квалифицируется как встроенное и поэтому представляется так, будто оно является непосредственным членом родительского пространства имен. Клиентский код, вызывающий 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 <typename T>
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 <typename T>
class Funcs
{
public:
Funcs(void);
T Add(T a, T b);
T Subtract(T a, T b);
T Multiply(T a, T b);
std::vector<double> Log(double);
T Accumulate(std::vector<T> nums);
};
}
}
Псевдонимы пространств имен
Имена пространств имен должны быть уникальными, из-за чего зачастую они получаются не слишком короткими. Если длина имени затрудняет чтение кода или утомительно вводить в файл заголовка, где нельзя использовать директивы, можно сделать псевдоним пространства имен, который служит сокращенным для фактического имени. Например:
namespace a_very_long_namespace_name { class Foo {}; }
namespace AVLNN = a_very_long_namespace_name;
void Bar(AVLNN::Foo foo){ }
анонимные или безымянные пространства имен
Вы можете создать явное пространство имен, но не присвоить ему имя.
namespace
{
int MyFunc(){}
}
Это называется неименованным или анонимным пространством имен, и это полезно, если вы хотите сделать объявления переменных невидимыми для кода в других файлах (т. е. дать им внутреннюю компоновку), не создавая именованное пространство имен. Весь код, находящийся в том же файле, может видеть идентификаторы в безымянном пространстве имен, но эти идентификаторы, а также само пространство имен, будет невидимым за пределами этого файла или, точнее, вне блока перевода.