Совет по пространствам имен C ++ - PullRequest
71 голосов
/ 03 апреля 2009

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

UPDATE

Для всех, кто интересуется, , вот как я в итоге занялся этой проблемой.

Ответы [ 9 ]

106 голосов
/ 03 апреля 2009

Пространства имен C ++ не предназначались для того, чтобы быть механизмом проектирования - они просто предназначены для предотвращения конфликтов имен. Вы действительно не хотите или не должны использовать вложенные пространства имен в 99,99% случаев.

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

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

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

Рассмотрев их, если вы все еще хотите использовать вложенные пространства имен всеми способами, сделайте это - нет ничего технически неправильного в их использовании таким образом.

23 голосов
/ 03 апреля 2009

Пространства имен C ++ значительно улучшились по сравнению с предыдущим предложением (т. Е. Вообще не было пространств имен). Пространства имен C # расширили концепцию и работают вместе с ней. Я бы посоветовал вам сохранить ваши пространства имен в простой плоской структуре.

РЕДАКТИРОВАТЬ Вы советуете, что из-за коротких событий, которые я изложил здесь?

Просто "Да". Пространства имен C ++ не были предназначены для того, чтобы помочь вам разделить логику и библиотеки так, как это делается в C #.

Цель пространств имен C ++ состоит в том, чтобы остановить реальную проблему, с которой сталкиваются разработчики C, где они сталкиваются с конфликтами имен при использовании двух сторонних библиотек, экспортирующих одинаковые имена функций. Разработчики C имели различные обходные пути для этого, но это могло быть серьезной болью.

Идея заключалась в том, что STL и т. Д. Имеют пространство имен std::, библиотеки, предоставляемые "XYZ Corp", будут иметь пространство имен xyz::, вы, работая в "ABC corp", поместите все ваши вещи в одном abc:: пространстве имен.

17 голосов
/ 14 ноября 2009

что я делаю, когда объявление вперед выглядит так:

 namespace abc { namespace sub { namespace subsub { class MyClass; }}}

Мои предварительные объявления свернуты в одну строку. Читаемость прямого объявления приносится в жертву взамен читаемости остальной части кода. И для определений я также не использую отступы:

 namespace abc {
 namespace sub {
 namespace subsub {

 class MyClass 
 {
    public:
       MyClass();

       void normalIntendationsHere() const;
 };

 }
 }
 }

Использование этого стиля требует немного дисциплины в начале, но это лучший компромисс для меня.

8 голосов
/ 03 апреля 2009

По крайней мере, небольшая помощь, в некоторых случаях вы можете сделать это:

namespace foo = A::B::C::D;

А затем ссылаться на A :: B :: C :: D как foo. Но только в некоторых случаях.

6 голосов
/ 21 ноября 2009

Вы можете пропустить отступ. Я часто пишу

namespace myLib { namespace details {

/* source code */

} } /* myLib::details */

Исходный код C ++ в конечном итоге компилируется в двоичный, в отличие от C # / Java, который остается в двоичном. Таким образом, пространство имен просто обеспечивает прекрасное решение для конфликта имен переменных. Он не предназначен для иерархии классов.

Я часто держу в коде один или два уровня пространства имен.

4 голосов
/ 03 апреля 2009

Прежде всего вы можете избежать отступов в пространстве имен, потому что для этого нет причин.

Использование пространств имен в примерах не показывает силу пространств имен. И их сила, как по мне, делит доменные зоны одна на другую. Отделите служебные классы от бизнес-классов.

Только не смешивайте разные иерархии пространств имен в одном .h файле. Пространства имен являются своего рода дополнительным комментарием для вашего интерфейса объявления функций. Взгляд на пространства имен и имена классов должен многое объяснить.

namespace product
{
namespace DAO
{

class Entity
{
};
0 голосов
/ 21 мая 2014

Я обнаружил, что вы можете имитировать пространство имен 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», что было бы более логично, поскольку это путь к классам, а не для имена пространств, где каждое пространство может иметь одинаковые имена

Надеюсь, это кому-нибудь поможет

Я забыл сказать, что все эти способы действительны, и умеренное использование первых двух может быть включено в третий для создания библиотеки, которая имеет смысл, т. Е. (Не очень хороший пример)

_INT::POINT2{}

и

_DOUBLE::POINT2{}

, чтобы вы могли изменить уровень точности с помощью

#define PREC _DOUBLE 
// or #define PREC _INT 

и затем создание экземпляра PREC :: POINT2 для двойной точности POINT2

Это нелегко сделать с пространствами имен c # или java

очевидно, это только один пример. Подумайте, как читается использование.

0 голосов
/ 30 мая 2012

Иногда я объявляю глубокие пространства имен как пару макросов в отдельном заголовке

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;

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

0 голосов
/ 03 апреля 2009

Вы чрезмерно используете их (и ничего не получите взамен).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...