Вот несколько причин, почему и как пространства имен C ++ отличаются от пространств имен Java или C #.
Предотвращение конфликтов
В языках Java / C # пространства имен предназначены для избежания конфликтов между именами в разных частях библиотек классов. У вас может быть класс «Watcher» в 5 разных местах иерархии пространства имен в C #. В C ++, если у вас есть классы с одинаковыми именами, встречающиеся в вашей библиотеке, вы помещаете внутрь другого класса вместо создания пространств имен. Такие вложенные классы хороши и приветствуются, и фактически синтаксис также обрабатывает, как будто класс является пространством имен, используя :: operator.
Сколько должно быть вложенных пространств имен?
Популярные библиотеки, такие как Boost, Eigen и, конечно, STL, дают хорошие примеры. в этих библиотеках, как правило, содержится почти все содержимое одного пространства имен, например std::
или boost::
или eigen::
. Немногие компоненты получают свое собственное пространство имен, например std::ios
или boost:filesystem
. Не существует согласованных правил относительно того, когда использовать второй уровень, но кажется, что большие или отдельно разработанные / поддерживаемые или дополнительные компоненты обычно получают свои собственные пространства имен. Третий уровень еще более редок. Обычно я использую структуру company::project
и для большой независимо используемой подсистемы проектов company::project::component
.
Предотвращение конфликтов во внешних библиотеках
Теперь главный вопрос: что если вы получите две библиотеки от двух разных людей, которые имеют одинаковые пространства имен и классы? Такая ситуация довольно редкая, потому что большинство людей, как правило, оборачивают свои библиотеки, по крайней мере, в название своего проекта Даже если имена проектов совпадают, еще реже вы используете библиотеки из обоих. Однако иногда плохие решения принимаются для имен проектов (ааа ... "metro", "apollo" ...) или даже пространства имен просто не используются вообще. Если это произойдет, вы включите #include для одной или обеих библиотек в пространство имен, и конфликт разрешится! Это одна из причин, почему люди не слишком беспокоятся о конфликтах, потому что их разрешение тривиально. Если вы будете следовать практике использования company::project
, то конфликты станут очень редкими.
Различия в языках
Хотя C ++ предоставляет оператор using namespace
точно так же, как C #, обычно считается плохой практикой «импортировать» все в собственное пространство имен. Причиной этого является то, что заголовок может содержать много «плохих» вещей, включая переопределение вещей, которые могут вас полностью удивить. Это совсем не похоже на C # / Java, где вы получаете чистый открытый интерфейс только тогда, когда вы делаете эквивалент using namespace
. (примечание: в C ++ вы можете достичь того же самого, используя шаблон Pimpl, но обычно это слишком много лишних операций и фактически не все библиотеки делают это). Таким образом, вы почти никогда не хотите делать using namespace
. Вместо этого вы делаете typedefs
(или using name =
) для того, что вы действительно хотите использовать. Это снова делает нецелесообразным использование глубоко вложенных пространств имен.
Организационный код
В Java / C # люди часто упорядочивают код в папках. Обычно, когда папка содержит более 20 или даже 10 файлов, люди начинают задумываться о папках. В C ++ все более разнообразно , но для многих крупных проектов предпочтительнее более плоские структуры каталогов. Например, папка std стандартной библиотеки содержит 53 файла, а проект Facebook folly , похоже, идет по тому же пути. Я думаю, что одной из причин этого, вероятно, является тот факт, что люди Java / C # чаще используют визуальные IDE и используют прокрутку мыши в навигации по папкам, а не в консоли, где вы можете использовать подстановочные знаки для поиска файла в плоской структуре. Кроме того, программисты на C ++ абсолютно не уклоняются от помещения нескольких классов в один файл и именования файла как логической единицы, а не имени класса в отличие от C # или Java. Это ускоряет компиляцию, что очень важно для больших проектов. Несмотря на то, что для уровня языка нет необходимости иметь собственное пространство имен для каждой папки, многие разработчики C ++ предпочитают назначать свое собственное пространство имен для каждой папки и поддерживать иерархию папок на уровне 2 или менее.
Возможное исключение
В C ++ вы можете ссылаться на A::B::C::D
как просто C::D
, если вы уже находитесь внутри A::B
. Поэтому, если у вас есть закрытый код или менее используемые классы, которые вы хотите продвинуть дальше вниз, вы можете сделать это, сохраняя при этом собственную относительную глубину до 2 или около того. В этом случае вы также можете создать папку для каждого уровня, чтобы расположение файлов было предсказуемым. В целом, в этой области нет золотых стандартов, но вы не хотите зацикливаться на глубоко вложенных пространствах имен, имитирующих C # / Java.
Относящиеся