Подтвердить что ты не робот

Пространства имен С++, сравнение с пакетами Java

Недавно я сделал кучу Java-кодирования и привык к очень конкретным системам именования пакетов с глубоким вложением, например. com.company.project.db. Это отлично работает в Java, AS3/Flex и С#. Я также видел ту же парадигму, что и на С++, но я также слышал, что это плохо, чтобы рассматривать пространства имен С++ как прямые копии пакетов Java.

Это правда и почему? Как пространства имен и пакеты одинаковы и разные? Какие проблемы могут возникнуть, если вы используете глубокие вложенные пространства имен?

4b9b3361

Ответ 1

В пространствах имен С++ речь идет только о разделении доступных имен. Пакеты Java - это модули. Иерархия именования - всего лишь один из аспектов.

В С++ нет ничего плохого, с глубоко вложенными пространствами имен, за исключением того, что они обычно не нужны, поскольку за ними нет системной системы, а дополнительные слои просто добавляют шум. Обычно этого достаточно, чтобы иметь один или два уровня пространства имен, с нечетным дополнительным уровнем для внутренних деталей (часто называемых только деталями).

Существуют также дополнительные правила для пространств имен С++, которые могут вас поймать, если они используются, например аргумент-зависимый поиск, а также правила вокруг разрешение на родительские уровни. WRT, возьмите:

namespace a{ namespace b{ int x; } }
namespace b{ string x; }
namespace a
{
  b::x = 42;
}

Является ли это законным? Является ли это очевидным, что происходит? Вам необходимо знать точность разрешения пространства имен для ответа на эти вопросы.

Ответ 2

Пакеты Java не вложены, они плоские. Любая видимая вложенность - не более чем соглашение об именах.

Например, пакет com.company.project.db не имеет отношения к com.company.project или com.company.project.db.x. Код в com.company.project.db больше не имеет доступа к коду в com.company.project.db.x, чем код в a.b.c.

Ответ 3

У вас могут быть вложенные пространства имен в С++.

Они не работают так же, как в java, хотя, очевидно. Пакеты Java на самом деле намного лучше определены, и нет реальной статической инициализации. С пространствами имен С++ полезны, но все еще имеют справедливую часть опасности.

Ответ 4

В С++ основной единицей проектирования и реализации является класс, а не пространство имен. Пространства имен были предназначены для предотвращения конфликтов имен в больших библиотеках, а не для выражения понятий.

Классы имеют несколько преимуществ по сравнению с пространствами имен:

  • у них могут быть конструкторы и деструкторы
  • у них могут быть закрытые члены
  • они не могут быть повторно открыты.

Однако, я бы дважды посмотрел на любые глубоко вложенные отношения. Это не очень хороший способ разработки программного обеспечения и приводит к нечитаемому коду, независимо от того, используете ли вы классы или пространства имен.

Ответ 5

Я брошу пару вещей, которые я слышал, но не знаю правдивости, пожалуйста, помогите подтвердить/развеять их.

  • Производительность С++ (каким-то образом) затрагивается длинными полностью указанными именами методов, например, namespace1::namespace2::namespace3::classX::method123()

  • Вы можете ограничить допустимую длину символа в компиляторе/компоновщике

Ответ 6

Я думаю, что в предыдущих ответах что-то не хватает, и это одна из причин, по которой мне очень нравится С++.

Представьте, что вы программируете графическое приложение, и вдруг вы осознаете, что среди всех ваших виджетов есть что-то общее. Вы хотите, чтобы все они имели новую функцию. Что вы делаете?

1) Отредактируйте базовый класс виджетов? Хорошо, но, скорее всего, у вас нет доступа к нему. Возможно, есть проблема с лицензированием, которая мешает вам выполнять свою собственную модификацию. Даже если вы можете просто сделать это, если это то, что имеет смысл только для вашего проекта, авторы не будут включать его в свой будущий выпуск, а обновление инструментария будет более болезненным.

2) Создайте класс интерфейса/мультинаследование? В зависимости от вашего существующего кода будет больш-больно обновлять каждый класс, связанный с виджетами. Сделайте это, и ваш код будет стоить дороже, потому что все, определяющие новый класс, должны знать, что они предположительно наследуют от вашего интерфейса. Стать зависимым от дисциплины других людей очень рискованно.

Замечательная вещь в пространствах имен С++ заключается в том, что у вас есть дополнительный способ инкапсулировать материал в уже существующую систему. Не только вы можете инкапсулировать в уже существующие библиотеки, которые вы не можете редактировать, вы можете инкапсулировать аналогичные концепции, которые вы не можете легко вставить в свою иерархию классов/объектов.

Java заставляет вас больше ориентироваться на чистый дизайн ООП. Уверен, что я говорю вам, что вы грязный хак и не изящный, но есть много ленивых программистов, которые не тратят время на разработку своих проектов.

Ответ 7

Вот несколько причин, почему и как пространства имен С++ отличаются от пространства имен Java или С#.

Предотвращение конфликтов

В языках Java/С# пространства имен предназначены для предотвращения конфликтов между именами в разных частях библиотек классов. У вас может быть класс под названием "Наблюдатель" в 5 разных местах иерархии пространства имен в С#. В С++, если у вас одинаковые именованные классы, встречающиеся в вашей библиотеке, вы помещаете внутри другого класса вместо создания пространств имен. Такие вложенные классы прекрасно и поощряются, и на самом деле синтаксис также рассматривает, как если бы класс был пространством имен с использованием:: operator.

Сколько вложенных пространств имен должно быть?

Популярные библиотеки, такие как Boost, Eigen и, конечно же, STL - хорошие примеры. эти библиотеки, как правило, содержат почти все содержимое одного пространства имен, например std:: или boost:: или eigen::. Немногие компоненты получают свое собственное пространство имен, например std::ios или boost:filesystem. Не существует согласованных правил, когда использовать второй уровень, но он кажется большим или раздельно разработанным/поддерживаемым, или необязательные компоненты обычно получают свои собственные пространства имен. Третий уровень еще реже. Обычно я использую структуру company::project и для большой независимо используемой подсистемы проектов company::project::component.

Предотвращение конфликтов во внешних библиотеках

Теперь большой вопрос: что, если вы получаете две библиотеки от двух разных людей, которые имеют одинаковые пространства имен и классы? Эта ситуация довольно редка, потому что большинство людей склонны обертывать свои библиотеки по крайней мере в имени своего проекта. Даже если имена проектов одинаковые, еще реже, что вы в конечном итоге используете библиотеки из обоих. Однако иногда принимаются неправильные решения для названий проектов (ahm... "metro", "apollo"...) или даже пространства имен просто не используются вообще. Если это произойдет, вы переносите #include для обеих или обеих библиотек в пространство имен, и конфликт разрешен! Это одна из причин, почему люди не слишком беспокоятся о конфликтах, потому что их решение тривиально. Если вы следуете практике использования company::project, тогда конфликты становятся очень редкими.

Различия в языках

Хотя С++ предоставляет инструкцию using namespace точно так же, как и С#, ее обычно считают плохой практикой "импортировать" все в ваше собственное пространство имен. Причина этого в том, что заголовок может содержать много "плохих" вещей, включая переопределение вещей, которые могут вас полностью удивить. Это совсем не похоже на С#/Java, где вы получаете чистый публичный интерфейс, когда вы выполняете эквивалент using namespace. (обратите внимание: на С++ вы можете добиться того же, используя шаблон Pimpl, но обычно это слишком большая часть дополнительной сантехники, и на самом деле это делают немногие библиотеки). Поэтому вы почти никогда не хотите делать using namespace. Вместо этого вы делаете typedefs (или using name =) за то, что вы действительно хотите использовать. Это снова делает невозможным использование глубоко вложенных пространств имен.

Организация кода

В Java/С# люди часто организуют код в папках. Обычно, когда папка насчитывает более 20 или даже 10 файлов, люди начинают думать о папках. В С++ вещи более разнообразны, но для многих крупных проектов предпочтительны более плоские структуры каталогов. Например, стандартная библиотека std folder имеет 53 файла и Facebook folly, похоже, идет по тому же маршруту. Я думаю, что одной из причин этого, вероятно, является тот факт, что люди Java/С# используют визуальные IDE больше и используют прокрутки мыши в навигации по папкам, а не консоль, где вы можете использовать wild cards для поиска файла в плоской структуре. Кроме того, программисты на C++ абсолютно не уклоняются от размещения нескольких классов в одном файле и имени файла как логической единицы, а не как имя класса, в отличие от С# или Java. Это ускоряет сборку, что очень важно для крупных проектов. Несмотря на отсутствие требований к языковому уровню для наличия собственного пространства имен для каждой папки, многие разработчики С++ предпочитают назначать свое собственное пространство имен для каждой папки и поддерживать иерархию папок на уровне 2 или менее.

Возможное исключение

В С++ вы можете ссылаться на A::B::C::D как на C::D, если вы уже находитесь внутри A::B. Поэтому, если у вас есть закрытый код или менее используемые классы, которые вы хотите продвигать дальше, вы можете сделать это, сохраняя при этом свою собственную относительную глубину до 2 или около того. В этом случае вам также может понадобиться создать папку для каждого уровня, чтобы расположение файлов было предсказуемым. В общем, в этой области нет золотых стандартов, но вы не хотите переходить за борт с глубоко вложенными пространствами имен, имитирующими С#/Java.

Похожие