Советы по пространствам имен 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++? Или обычно только одиночные (не вложенные) пространства имен?



обновление



для тех, кто заинтересован, вот как я оказался решение этой проблемы.

584   9  

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

    Ничего не найдено.