Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
#include "Sales_data.h"
namespace cplusplus_primer {
// определения членов класса Sales_data и перегруженных операторов
}
Использующая эту библиотеку программа включила бы все необходимые заголовки. Имена в этих заголовках определены в пространстве имен cplusplus_primer:
// ---- user.cc ----
// имена заголовка Sales_data.h находятся в пространстве
// имен cplusplus_primer
#include "Sales_data.h"
int main() {
using cplusplus_primer::Sales_data;
Sales_data trans1, trans2;
// ...
return 0;
}
Подобная организация программы придает библиотеке свойство модульности, необходимое как разработчикам, так и пользователям. Каждый класс организован в виде двух файлов: интерфейса и реализации. Пользователь одного класса вовсе не должен использовать при компиляции другие классы. Их реализацию можно скрыть от пользователей, разрешив при этом компилировать и компоновать файлы Sales_data.cc и user.cc в одну программу, причем без опасений по поводу возникновения ошибок во время компиляции или компоновки. Кроме того, разработчики библиотеки могут работать над реализацией каждого класса независимо.
В использующую эту библиотеку программу следует подключить все необходимые заголовки. Имена в этих заголовках определены в пространстве имен cplusplus_primer.
Следует заметить, что директивы #include обычно не помещают в пространство имен. Если попробовать сделать это, то произойдет попытка определения всех имен в этом заголовке как членов окружающего пространства имен. Например, если бы файл Sales_data.h открыл пространство имен cplusplus_primer прежде, чем включить заголовок string, то в программе была бы ошибка, поскольку это привело бы к попытке определить пространство имен std в пространстве имен cplusplus_primer.
Определение членов пространства именЕсли объявления находятся в области видимости, то код в пространстве имен может использовать короткую форму имен, определенных в том же (или вложенном) пространстве имен:
#include "Sales_data.h"
namespace cplusplus_primer { // повторное открытие cplusplus_primer
// члены, определенные в пространстве имен, могут использовать имена
// без уточнений
std::istream&
operator>>(std::istream& in, Sales_data& s) { /* ... */}
}
Член пространства имен может быть также определен вне определения пространства имен. Для этого применяется подход, подобный определению членов класса вне его. Объявление пространства имен должно находиться в области видимости, а в определении следует указать пространство имен, которому принадлежит имя.
// члены пространства имен, определенные вне его, должны использовать
// полностью квалифицированные имена
cplusplus_primer::Sales_data
cplusplus_primer::operator+(const Sales_data& lhs,
const Sales_data& rhs) {
Sales_data ret(lhs);
// ...
}
Подобно членам класса, определенным вне самого класса, когда встречается полностью определенное имя, оно находится в пределах пространства имен. В пространстве имен cplusplus_primer можно использовать другие имена членов пространства имен без квалификации. Таким образом, хотя класс Sales_data является членом пространства имен cplusplus_primer, для определения параметров его функций можно использовать его имя без квалификации.
Хотя член класса пространства имен может быть определен вне его определения, такие определения должны присутствовать в окружающем пространстве имен. Таким образом, оператор operator+ класса Sales_data можно определить в пространстве имен cplusplus_primer или в глобальной области видимости. Но он не может быть определен в несвязанном пространстве имен.
Специализация шаблонаСпециализация шаблона должна быть определена в том же пространстве имен, которое содержит первоначальный шаблон (см. раздел 16.5). Подобно любым другим именам пространства имен, пока специализация объявлена в пространстве имен, ее можно определить вне пространства имен:
// специализацию нужно объявить как член пространства std
namespace std {
template <> struct hash<Sales_data>;
}
// добавив объявление для специализации к пространству std,
// специализацию можно определить вне пространства имен std
template <> struct std::hash<Sales_data> {
size_t operator()(const Sales_data& s) const {
return hash<string>()(s.bookNo) ^
hash<unsigned>()(s.units_sold) ^
hash<double>()(s.revenue);
}
// другие члены как прежде
};
Глобальное пространство именИмена, определенные в глобальной области видимости (т.е. имена, объявленные вне любого класса, функции или пространства имен), определяются в глобальном пространстве имен (global namespace). Глобальное пространство имен неявно объявляется и существует в каждом приложении. Каждый файл, который определяет сущность в глобальной области видимости (неявно), добавляет ее имя к глобальному пространству имен.
Для обращения к членам глобального пространства имен применяется оператор области видимости (оператор ::) (scope operator). Поскольку глобальное пространство имен неявно, у него нет имени.
Форма записи при обращении к члену глобального пространства имен имеет следующий вид.
::член_имя
Вложенные пространства именВложенное пространство имен (nested namespace) — это пространство имен, определенное в другом пространстве имен:
namespace cplusplus_primer {
// первое вложенное пространство имен: определение части
// библиотеки Query
namespace QueryLib {
class Query { /* ... */ };
Query operator&(const Query&, const Query&);
// ...
}
// второе вложенное пространство имен: определение части
// библиотеки Sales_data
namespace Bookstore {
class Quote { /* ... */ };
class Disc_quote : public Quote { /* ... */ };
// ...
}
}
Вложенное пространство имен — это вложенная область видимости, ее область видимости вкладывается в пределы содержащего ее пространства имен. Имена вложенных пространств имен подчиняются обычным правилам: имена, объявленные во внутреннем пространстве имен, скрывают объявления того же имени во внешнем пространстве. Имена, определенные во вложенном пространстве имен, являются локальными для внутреннего пространства имен. Код во внешних частях окружающего пространства имен может обратиться к имени во вложенном пространстве имен только через его квалифицированное имя. Например, имя класса QueryLib, объявленного во вложенном пространстве имен, выглядит следующим образом:
cplusplus_primer::QueryLib::Query
Встраиваемые пространства именНовый стандарт ввел новый вид вложенного пространства имен — встраиваемое пространство имен (inline namespace). В отличие от обычных вложенных пространств имен, имена из встраиваемого пространства имен применяются так, как будто они являются непосредственными членами окружающего пространства имен. Таким образом, нет необходимости в квалификации имен из встраиваемого пространства имен. Для доступа к ним достаточно использовать имя окружающего пространства имен.
Для определения встраиваемого пространства имен ключевое слово namespace предваряется ключевым словом inline:
inline namespace FifthEd {
// пространство имен для кода Primer Fifth Edition
}
namespace FifthEd { // неявно встраиваемая
class Query_base { /* ... */};
// другие объявления, связанные с классом Query
}
Это ключевое слово должно присутствовать в первом определении пространства имен. Если пространство имен вновь открывается позже, ключевое слово inline не обязательно, но может быть повторено.
Встраиваемые пространства имен зачастую используются при изменении кода от одного выпуска приложения к следующему. Например, весь код текущего издания Вводного курса можно поместить во встраиваемое пространство имен. Код предыдущих версий был бы в обычных, а не встраиваемых пространствах имен:
namespace FourthEd {
class Item_base { /* ... */};