Резюме
Функции, не являющиеся членами и разработанные как часть интерфейса класса X
(в особенности операторы и вспомогательные функции), должны быть определены в том же пространстве имен, что и X
, что обеспечивает их корректный вызов.
Обсуждение
Открытый интерфейс класса образуют не только открытые функции-члены, но и функции, не являющиеся членами. Принцип Интерфейса гласит: для класса X
все функции (включая функции, не являющиеся членами), которые "упоминают X
" и "поставляются вместе с X
" в одном и том же пространстве имен, являются логической частью X
, поскольку образуют часть интерфейса X
(см. рекомендацию 44 и [Sutter00]).
Язык С++ спроектирован с явным учетом Принципа Интерфейса. Причина, по которой в язык добавлен поиск, зависящий от аргумента (argument-dependent lookup — ADL), известный также как поиск Кёнига, заключается в том, чтобы обеспечить коду, использующему объект x
типа X
, возможность работать с частью его интерфейса, состоящей из функций, не являющихся членами (например, инструкция cout << x
использует оператор operator<<
, который не является членом класса X
) так же легко, как и функции-члены (например, вызов x.f()
) не требует выполнения специального поиска, поскольку очевидно, что поиск f
выполняется в области видимости X
). ADL обеспечивает для свободных функций, которые получают объект X
в качестве аргумента и поставляются вместе с определением X
ту же простоту использования, что и для функций-членов интерфейса X
. Одним из главных мотивов принятия ADL был, в частности, класс std::string
(см. [Sutter00]).
Рассмотрим класс X
, определенный в пространстве имен N:
class X {
publiс:
void f();
};
X operator+(const X&, const X&);
В вызывающей функции обычно пишется код наподобие x3=x1+x2
, где x1
, x2
и x3
— объекты типа X
. Если оператор operator+
объявлен в том же пространстве имен, что и X
, никаких проблем не возникает, и такой код отлично работает, поскольку оператор operator+
будет легко найден с помощью ADL.
Если же оператор operator+
не объявлен в том же пространстве имен, что и X
, вызывающий код работать не будет. В этом случае имеется два способа заставить его заработать. Первый состоит в использовании явно квалифицированного оператора
x3 = N::operator+(x1, x2);
Грустная картина — невозможность использовать естественный синтаксис оператора, который, собственно, и был главной целью введения перегрузки операторов в язык программирования. Другой способ заставить работать приведенный ранее код — использовать инструкцию using
:
using N::operator+;
// или: using namespace N;
x3 = x1 + x2;
Применение using
— совершенно нормальная и приемлемая вещь (см. рекомендацию 59), но все проблемы решаются гораздо проще, если автор X
изначально поступает корректно и помещает оператор operator+
, работающий с объектами X
, в то же пространство имен, где находится X
.
"Оборотная сторона" этого вопроса рассматривается в рекомендации 58.
Примеры
Пример 1. Операторы. Операторы работы с потоками operator<<
и operator>>
для объектов некоторого класса X
, вероятно, относятся к наиболее ярким примерам функций, которые вполне очевидно являются частью интерфейса класса X
, но при этом всегда представляют собой свободные функции (это обязательное условие, поскольку левый аргумент этих операторов — поток, а не объект X
). Та же аргументация применима и к другим операторам, не являющимся членами X
. Убедитесь, что ваши операторы находятся в том же пространстве имен, что и класс, с которым они работают. Если у вас есть возможность выбора, лучше делать операторы и все прочие функции не членами и не друзьями класса (см. рекомендацию 44).
Пример 2. Прочие функции. Если автор X
предоставляет именованные вспомогательные функции, которые получают в качестве аргументов объекты X
, они должны находиться в том же пространстве имен, что и X
. В противном случае вызывающий код, использующий объекты X
, будет не в состоянии работать с этими именованными функциями без явной квалификации их имен или применения инструкции using
.
Ссылки
[Stroustrup00] §8.2, §10.3.2, §11.2.4 • [Sutter00] §31-34
58. Храните типы и функции в разных пространствах имен, если только они не предназначены для совместной работы
Читать дальше