Инструменты пользователя

Инструменты сайта


examination:oop:question54

Пространства имен: назначение, синтаксис определения.

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

Например, Андрей работает в компании X, а ID (сокр. от англ. Identifier — идентификатор) его как работника равен 123. Олег работает в компании Y, а его ID также равен 123. Единственное (с точки зрения некоей системы учета), благодаря чему Андрей и Олег могут быть различимы при совпадающих ID, это их принадлежность к разным компаниям. Различие компаний в этом случае представляет собой систему различных пространств имён (одна компания — одно пространство). Наличие двух работников в компании с одинаковыми ID представляет большие проблемы при их использовании, например, по платёжному чеку, в котором будет указан работник с ID 123, будет весьма затруднительно определить работника, которому этот чек предназначается.

В языках программирования одним из способов задания границы пространства имен может быть использование т. н. области видимости.

namespace Namespace12
{
  int foo;
}
 
void func1()
{
  using namespace Namespace12;
  // теперь все имена из пространства имён Namespace12 будут видны здесь без дополнительных префиксов
 
  ++foo;
}
 
void func2()
{
  // а тут имя нужно уточнить:
  Namespace12::foo = 42;
}

Код, не объявленный явным образом в пространстве имён, подразумевается объявленным в глобальном пространстве имён.

Разрешение пространств имён в C++ иерархично. Это означает, что в гипотетическом пространстве имён еда::суп, идентификатор курица будет обозначать еда::суп::курица (если пространство существует). Если не существует, то тогда он указывает на еда::курица (если это пространство существует). Если и это пространство не существует, то курица ссылается на идентификатор в глобальном пространстве.

Хотя пространства имён широко используются в современном коде, большая часть старого кода не имеет подобных возможностей. Например, вся стандартная библиотека языка C++ определена внутри namespace std, но до стандартизации многие компоненты первоначально были определены в глобальном пространстве.

В С++ вы можете поместить свою функцию в пространство имен, как бы расширить ее имя

namespace my_funcs {
  long random() { ... };
};

и после этого использовать следующим образом:

long l;
l = my_funcs::random();

Здесь :: (двойное двоеточие) - оператор разрешения области видимости (scope resolution operator).

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

l = std::random(); // из stdlib
l = my_funcs::random(); // my own function

Указывать для каждой функции пространство имен довольно утомительно, так что вы с помощью директивы using можете сказать, какой именно функцией (или набором функций) хотите пользоваться:

using my_funcs::random;
using std::abs;

l = random(); // my_funcs::random()
l = abs(l); // std::abs();

Можно в директиве using поставить не имя функции, а все пространство имен, при этом все имена без :: будут ссылаться либо на функции в текущем файле (если они не вынесены, как my_funcs::random, в отдельное пространство имен), либо на пространство, указанное в директиве using:

using namespace std;
l = random(); // std::random()
l = abs(); // std::abs()

l = my_funcs::random(); // own function

До того, как был принят стандарт, довольно долго в С++ не было пространств имен, а стандартные файлы заголовков так же, как и в С, заканчивались суффиксом .h - например <iostream.h>.

С принятием стандарта все имена библиотеки вынесли в пространсво std, однако к тому времени на С++ было написано много программ и библиотек. И для того, чтобы сохранилась совместимость с ними, файлы заголовков пришлось исполнить в двух вариантах - в старом, с суффиксом .h, и в новом - вообще без суффикса. При этом к заголовкам, пришедшим из С, прибавили спереди букву c, например <stdio.h> превратился в <cstdio>. А у заголовков, которых в С не было, просто убрали суффикс - <iostream.h> стал называться <iostream>.

А разница между старым и новым набором очень простая - заголовок «старого» образца - это соответсвующий новый плюс директива using namespace std. Например, старая запись

#include <stdio.h> и более новая и правильная #include <cstdio> using namespace std; это одно и то же.

examination/oop/question54.txt · Последние изменения: 2014/01/15 12:22 (внешнее изменение)