Советы по пространствам имен C++
Я просто учу себя пространствам имен C++ (исходя из фона C#), и я действительно начинаю думать, что даже со всеми вещами, которые C++ делает лучше, чем большинство других языков, вложенные пространства имен не являются одним из них!
Я прав, думая, что для объявления некоторых вложенных пространств имен я должен сделать следующее:
namespace tier1
{
namespace tier2
{
namespace tier3
{
/* then start your normal code nesting */
}
}
}
против:
namespace tier1::tier2::tier3
{
}
à la C#?
это становится еще более сумасшедшим, когда мне нужно вперед заявляем:
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
вот почему вы не склонны видеть много использования пространств имен в примерах C++? Или обычно только одиночные (не вложенные) пространства имен?
обновление
для тех, кто заинтересован, вот как я оказался решение этой проблемы.
9 ответов:
пространства имен C++ не были предназначены для механизма проектирования - они существуют просто для предотвращения конфликтов имен. Вы действительно не хотите или должны использовать вложенные пространства имен в 99.99% ситуаций.
хорошим примером правильного использования пространств имен в C++ является стандартная библиотека C++. Все в этой довольно большой библиотеке помещается в одном пространстве имен под названием std - нет никакой попытки или необходимости разбивать библиотеку на (например) подпространство ввода-вывода, математику подпространство, подпространство контейнера и т. д.
основным инструментом моделирования в C++ является класс (и в некоторой степени шаблон), а не пространство имен. Если вы чувствуете необходимость в вложении, вы должны рассмотреть возможность использования вложенных классов, которые имеют следующие преимущества перед пространствами имен:
- у них есть методы
- они могут контролировать доступ к
- они не могут быть повторно открыт
рассмотрев их, если вы все еще хотите использовать вложенные пространства имен непременно делают это - нет ничего технически неправильного в их использовании таким образом.
пространства имен C++ были значительно улучшены по сравнению с предыдущим предложением (т. е. никаких пространств имен вообще). Пространства имен C# расширили концепцию и работали с ней. Я бы посоветовал вам сохранить ваши пространства имен в простой плоской структуре.
EDITвы советуете это из-за недостатков, которые я здесь изложил?
Просто "Да". Пространства имен C++ не были разработаны, чтобы помочь вам разделить вашу логику и библиотеки так, как они это делают С.#
цель пространств имен C++ - остановить проблему реального мира, с которой сталкиваются разработчики C, где они сталкиваются с конфликтами имен при использовании двух сторонних библиотек, которые экспортируют одни и те же имена функций. Разработчики C имеют различные обходные пути для этого, но это может быть серьезная проблема.
идея была в том, что STL etc имеет
std::пространство имен, библиотеки, предоставляемые "XYZ Corp" будет иметьxyz::пространство имен, вы работаете на "ABC corp" поставил бы все ваш вещи в одномabc::пространство имен.
что я делаю, когда вперед объявление выглядит так:
namespace abc { namespace sub { namespace subsub { class MyClass; }}}мои прямые объявления свернуты в одну строку. Читабельность прямого объявления приносится в жертву в обмен на читабельность остальной части кода. И для определений я тоже не использую отступы:
namespace abc { namespace sub { namespace subsub { class MyClass { public: MyClass(); void normalIntendationsHere() const; }; } } }используя этот стиль требует немного дисциплины в начале, но это лучший компромисс для меня.
по крайней мере, как небольшая помощь, в некоторых случаях вы можете сделать это:
namespace foo = A::B::C::D;а затем ссылка A:: B:: C:: D как foo. Но только в некоторых случаях.
отступ можно пропустить. Я часто пишу
namespace myLib { namespace details { /* source code */ } } /* myLib::details */исходный код C++ в конечном итоге компилируется в двоичный код, в отличие от C#/Java, который остается в двоичном коде. Поэтому пространство имен просто предоставляет прекрасное решение для конфликта имен переменных. Он не предназначен для иерархии классов.
Я часто оставляю один или два уровня пространства имен в коде.
прежде всего, вы можете избежать отступа пространства имен, потому что для этого нет причин.
использование пространств имен в примерах не будет показывать силу пространств имен. И их сила, как для меня, заключается в разделении доменных областей друг от друга. Отделите служебные классы от бизнес-классов.
просто не смешивайте различные иерархии пространств имен в одном .H-файл. Пространства имен являются своего рода дополнительным комментарием для вашего интерфейса объявления функций. Глядя На пространства имен и класса имена должны многое объяснить.
namespace product { namespace DAO { class Entity { };
я обнаружил, что вы можете как бы имитировать пространство имен c# вот так;
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*/и это все еще немного долго запыхался. но чувствует себя немного ОО.
и слышит, как кажется, лучше всего сделать
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++, как я бы с c#. Это было бы слишком долго, и никогда не будет работать так же, как пространства имен c#.
лучшее использование пространств имен в c++ - это прекратить говорить, что моя функция super cout (которая звенит каждый раз, когда ее вызывают) не смешивается с функцией std::cout (что гораздо менее впечатляет).
только потому, что c# и c++ имеют пространства имен, это не означает, что пространство имен значит то же самое. они разные, но похожи. Идея для пространств имен c# должна была исходить из пространств имен c++. кто-то, должно быть, видел, что может сделать похожая, но другая вещь, и у него не было достаточно силы воображения, чтобы дать ему свое собственное оригинальное имя, такое как "ClassPath", которое имело бы больше смысла как его путь к классам, а не для предоставления пространств имен, где каждое пространство может иметь одинаковые имена
надеюсь, это кому-то поможет
Я забыл скажем, что все эти способы действительны, и умеренное использование первых двух может быть включено в третий, чтобы создать библиотеку, которая имеет смысл ie (не отличный пример)
_INT::POINT2{}и
_DOUBLE::POINT2{}так что вы можете изменить уровень точности с помощью
#define PREC _DOUBLE // or #define PREC _INTа затем создать экземпляр PREC:: POINT2 для двойной точности POINT2
это не так просто сделать с пространствами имен c# или java
очевидно, что это только один образец. Подумайте о том, как читается использование.
Я иногда объявляю глубокие пространства имен как пару макросов в отдельном заголовке
пространство имен.h
#define NAMESPACE_TIER1_TIER2_TIER3 \ namespace tier1 { \ namespace tier2 { \ namespace tier3 { #define END_NAMESPACE_TIER1_TIER2_TIER3 }}}чтобы использовать его где-то еще:
другой файл.h
#include "./namespace.h" NAMESPACE_TIER1_TIER2_TIER3; /* Code here */ END_NAMESPACE_TIER1_TIER2_TIER3;избыточные точки с запятой после макроса должны избегать дополнительного отступа.
Comments