С++ 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;

Резервные точки с запятой после макроса должны избегать дополнительного отступа.