С++ namespaces advice
Я просто преподаю себе пространства имен С++ (исходя из фона С#), и я действительно начинаю думать, что даже со всеми вещами, которые С++ делает лучше, чем большинство других языков, вложенные пространства имен не являются одним из них!
Я правильно понимаю, что для объявления некоторых вложенных пространств имен я должен сделать следующее:
namespace tier1
{
namespace tier2
{
namespace tier3
{
/* then start your normal code nesting */
}
}
}
В отличие от:
namespace tier1::tier2::tier3
{
}
à la С#?
Это становится еще более сумасшедшим, когда мне нужно переслать объявление:
namespace tier1
{
namespace tier2
{
namespace forward_declared_namespace
{
myType myVar; // forward declare
}
namespace tier3
{
/* then start your normal code nesting */
class myClass
{
forward_declared_namespace::myType myMember;
}
}
}
}
Принимая во внимание, что типичная система, которую я разрабатываю, состоит из:
MyCompany::MySolution::MyProject::System::[PossibleSections]::Type
Вот почему вы не склонны часто использовать пространства имен в примерах на С++? Или обычно только одиночные (не вложенные) пространства имен?
UPDATE
Для всех, кого интересует, вот как я закончил работу, чтобы решить эту проблему.
Ответы
Ответ 1
Пространства имен С++ не были предназначены для создания механизма проектирования - они просто предотвращают столкновения имен. Вы действительно не хотите или должны использовать вложенные пространства имен в 99,99% ситуаций.
Хорошим примером правильного использования пространств имен в С++ является стандартная библиотека С++. Все в этой довольно большой библиотеке помещается в одно пространство имен с именем std - нет попытки или необходимости разбить библиотеку на (например) пространство под-имен ввода-вывода, пространство имен, пространство под-имен контейнеров и т.д.
Основным инструментом моделирования в С++ является класс (и в некоторой степени шаблон), а не пространство имен. Если вы чувствуете потребность в вложенности, вам следует рассмотреть возможность использования вложенных классов, которые имеют следующие преимущества перед пространствами имен:
- у них есть методы
- они могут контролировать доступ
- они не могут быть повторно открыты.
Рассмотрев их, если вы все равно хотите использовать вложенные пространства имен, сделайте это так - нет ничего технически неправильного в использовании их таким образом.
Ответ 2
Пространства имен С++ были существенным улучшением по сравнению с предыдущим предложением (т.е. ни одного пространства имен). Пространства имен С# расширили концепцию и побежали с ней. Я бы посоветовал вам сохранить пространство имен в простой плоской структуре.
РЕДАКТИРОВАТЬ Посоветуете ли вы, что из-за коротких выступлений, которые я описал здесь?
Просто "Да". Пространства имен С++ не были предназначены для того, чтобы помочь вам разбить вашу логику и библиотеки так, как они делают на С#.
Цель пространств имен С++ - остановить проблему реального мира, с которой сталкиваются разработчики C, где они сталкиваются с конфликтами имен при использовании двух сторонних библиотек, которые экспортируют одни и те же имена (имена) функций. Разработчики C имели различные обходные пути, но это могло быть серьезной болью.
Идея заключалась в том, что STL и т.д. имеют пространство имен std::
, libs, предоставленные "XYZ Corp", будут иметь пространство имен xyz::
, вы работаете для "ABC corp", поместите все ваши вещи в один abc::
Пространство имен.
Ответ 3
что я делаю, когда форвардное объявление выглядит следующим образом:
namespace abc { namespace sub { namespace subsub { class MyClass; }}}
Мои форвардные объявления сворачиваются в одну строку. Считываемость декларации вперёд приносится в жертву в обмен на читаемость остальной части кода. И для определений я также не использую отступы:
namespace abc {
namespace sub {
namespace subsub {
class MyClass
{
public:
MyClass();
void normalIntendationsHere() const;
};
}
}
}
Использование этого стиля требует немного дисциплины в начале, но это лучший компромисс для меня.
Ответ 4
По крайней мере, как небольшая помощь, в некоторых случаях вы можете сделать это:
namespace foo = A::B::C::D;
И тогда ссылка A:: B:: C:: D как foo. Но только в некоторых случаях.
Ответ 5
Прежде всего, вы можете избежать отступа пространства имен, потому что для этого нет причин.
Использование пространств имен в примерах не будет показывать силу пространства имен. И их сила, как и я, разделяет области домена друг от друга. Разделите классы утилиты из бизнес-приложений.
Просто не смешивайте разные иерархии пространства имен в одном файле .h. Пространства имен являются дополнительным комментарием для вашего интерфейса описания функций. Взгляд на пространства имен и имена классов должны объяснять многое.
namespace product
{
namespace DAO
{
class Entity
{
};
Ответ 6
Вы можете пропустить отступ. Я часто пишу
namespace myLib { namespace details {
/* source code */
}; }; /* myLib::details */
Исходный код С++ в конечном итоге скомпилирован в двоичный код, в отличие от С#/Java, который находится в двоичном формате. Поэтому пространство имен просто предоставляет прекрасное решение для конфликта имен с именами. Он не предназначен для иерархии классов.
Я часто сохраняю один или два уровня пространства имен в коде.
Ответ 7
Я обнаружил, что вы можете сортировать пространство имен С# следующим образом:
namespace ABC_Maths{
class POINT2{};
class Complex{};
}
namespace ABC_Maths_Conversion{
ABC_MATHS::Complex ComplexFromPOINT2(ABC_MATHS::POINT2)
{return new ABC_MATHS::Complex();}
ABC_MATHS::POINT4 POINT2FromComplex(ABC_MATHS::COMPLEX)
{return new ABC_MATHS::POINT2();}
}
namespace ABC
{
}
Но код, похоже, не очень аккуратный. и я ожидаю долгое использование
Лучше вложить столько функциональности в классы, что-то вроде
namespace ABC{
class Maths{
public:
class POINT2{};
class Complex:POINT2{};
class Conversion{
public:
static Maths.Complex ComplexFromPOINT2(MATHS.POINT2 p)
{return new MATHS.Complex();}
static MATHS.POINT2 POINT2FromComplex(MATHS.COMPLEX p)
{return new ABC::MATHS.POINT2();}// Can reference via the namespace if needed
} /*end ABC namespace*/
И это все еще немного затянуто. но чувствует себя немного OO.
И слышит, как это выглядит лучше всего
namespace ABC
{
class POINT2{};
class Complex:POINT2{};
Complex ComplexFromPOINT2(POINT2 p){return new Complex();}
POINT2 POINT2FromComplex(Complex){return new POINT2();}
}
слышит, как выглядят обычаи
int main()
{
ABC_Maths::Complex p = ABC_Maths_Conversion::ComplexFromPOINT2(new ABC_MATHS::POINT2());
// or THE CLASS WAY
ABC.Maths.Complex p = ABC.Maths.Conversion.ComplexFromPOINT2(new ABC.Maths.POINT2());
// or if in/using the ABC namespace
Maths.Complex p = Maths.Conversion.ComplexFromPOINT2(new Maths.POINT2());
// and in the final case
ABC::Complex p = ABC::ComplexFromPOINT2(new ABC::POINT2());
}
было интересно узнать, почему я никогда не использовал пространства имен С++, подобные я c С#. Это будет слишком длинным, и никогда не будет работать так же, как пространства имен С#.
наилучшее использование пространств имен в С++ заключается в том, чтобы перестать говорить, что моя функция супер-cout (которая звонит каждый раз, когда ее вызвал) смешивается с функцией std:: cout (что гораздо менее впечатляет).
Просто потому, что С# и С++ имеют пространства имен, это не означает, что пространство имен означает одно и то же. они разные, но похожие. Идея для пространств имен С# должна быть из пространств имен С++. кто-то, должно быть, видел то, что мог сделать подобный, но другой способ, и не хватило достаточной силы воображения, чтобы дать ему свое собственное оригинальное имя, такое как "ClassPath", которое было бы более разумным как его путь к классам, а не для предоставления пространства имен, где каждое пространство может иметь одинаковые имена
Я надеюсь, что это поможет кому-то
Я забыл сказать, что все эти способы действительны, и умеренное использование первых двух может быть включено в третье, чтобы создать библиотеку, которая имеет смысл, то есть (не большой пример).
_INT::POINT2{}
и
_DOUBLE::POINT2{}
чтобы вы могли изменить уровень точности с помощью
#define PREC _DOUBLE
// or #define PREC _INT
а затем создав экземпляр PREC:: POINT2 для двойной точности POINT2
Это непростая задача для пространства имен С# или java
очевидно, что только один пример. Подумайте о том, как читается использование.
Ответ 8
Вы переработали их (и вы не получите ничего взамен).
Ответ 9
Я иногда объявляю глубокие пространства имен как пару макросов в отдельном заголовке
namespace.h
#define NAMESPACE_TIER1_TIER2_TIER3 \
namespace tier1 { \
namespace tier2 { \
namespace tier3 {
#define END_NAMESPACE_TIER1_TIER2_TIER3 }}}
Чтобы использовать его в другом месте:
anotherfile.h
#include "./namespace.h"
NAMESPACE_TIER1_TIER2_TIER3;
/* Code here */
END_NAMESPACE_TIER1_TIER2_TIER3;
Резервные точки с запятой после макроса должны избегать дополнительного отступа.