C ++命名空间建议

时间:2009-04-03 12:23:39

标签: c++ namespaces

我只是在教自己C ++命名空间(来自C#背景),我真的开始认为即使C ++比大多数其他语言做得更好,嵌套命名空间也不是其中之一!

我是否正确地认为为了声明一些嵌套的命名空间,我必须执行以下操作:

namespace tier1
{
    namespace tier2
    {
        namespace tier3
        {
            /* then start your normal code nesting */
        }
    }
}

相反:

namespace tier1::tier2::tier3
{
}

àlaC#?

当我需要转发声明时,这变得更加疯狂:

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 ++示例中看到很多名称空间的使用?或者通常只有单个(非嵌套)命名空间?

更新

对于任何有兴趣的人,this is how I ended up解决这个问题。

9 个答案:

答案 0 :(得分:106)

C ++命名空间并不是一种设计机制 - 它们只是为了防止名称冲突。在99.99%的情况下,你真的不想或不需要使用嵌套的命名空间。

在C ++中正确使用名称空间的一个很好的例子是C ++标准库。这个相当大的库中的所有内容都放在一个名为 std 的命名空间中 - 没有尝试或需要将库分解为(例如)I / O子命名空间,数学子命名空间,容器子命名空间等。

在C ++中进行建模的基本工具是类(在某种程度上是模板),而不是命名空间。如果您觉得需要嵌套,则应考虑使用嵌套类,这些类比命名空间具有以下优点:

  • 他们有方法
  • 他们可以控制访问权限
  • 他们无法重新开放

考虑到这些之后,如果您仍然希望通过各种方式使用嵌套命名空间 - 以这种方式使用它们在技术上没有任何问题。

答案 1 :(得分:23)

C ++命名空间是对先前产品的巨大改进(即根本没有命名空间)。 C#命名空间扩展了概念并使用它运行。我建议你将命名空间保存在一个简单的扁平结构中。

编辑 您是否建议由于我在此处列出的缺点?

简单地说“是”。 C ++命名空间的设计不是为了帮助您对逻辑进行分区。库在C#中的表现方式。

C ++命名空间的目的是阻止C开发人员遇到的现实问题,当使用两个导出相同功能名称的第三方库时,他们会遇到名称冲突。 C开发人员有各种解决方法,但这可能是一个严重的痛苦。

这个想法是STL等有std::命名空间,“XYZ Corp”提供的lib将有xyz::命名空间,你为“ABC corp”工作会把全部< / em>您在单个abc::命名空间中的内容。

答案 2 :(得分:17)

我向前宣告的行为如下:

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

我的前瞻性声明被折叠成一行。前提声明的可读性被牺牲,以换取其余代码的可读性。对于定义,我不使用缩进:

 namespace abc {
 namespace sub {
 namespace subsub {

 class MyClass 
 {
    public:
       MyClass();

       void normalIntendationsHere() const;
 };

 }
 }
 }

使用这种风格在开始时需要一些纪律,但这对我来说是最好的妥协。

答案 3 :(得分:8)

至少作为一个小帮助,在某些情况下你可以这样做:

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

然后引用A :: B :: C :: D作为食物。但只是在某些情况下。

答案 4 :(得分:5)

您可以跳过缩进。我经常写

namespace myLib { namespace details {

/* source code */

} } /* myLib::details */

C ++源代码最终被编译成二进制文件,而C#/ Java则保留在二进制文件中。因此,命名空间只为变量命名冲突提供了一个很好的解决方案。它不适用于类层次结构。

我经常在代码中保留一个或两个命名空间级别。

答案 5 :(得分:4)

首先,您可以避免命名空间缩进,因为没有理由这样做。

在示例中使用命名空间不会显示命名空间的功能。而他们的力量就是将领域区域彼此分开。将实用程序类划分为业务类。

不要在一个.h文件中混合使用不同的命名空间层次结构。命名空间是函数声明接口的额外注释。查看名称空间和类名应该解释很多东西。

namespace product
{
namespace DAO
{

class Entity
{
};

答案 6 :(得分:0)

我发现你可以像这样模仿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*/

这仍然有点长啰嗦。但感觉有点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#那样使用c ++命名空间。它会缠绕太长时间,并且永远不会像c#名称空间那样工作。

c ++中命名空间的最佳用法是停止说我的超级cout函数(每次调用时都会调用)与std :: cout函数混淆(这远远不那么令人印象深刻)。

仅仅因为c#和c ++具有命名空间,并不意味着命名空间意味着同样的事情。它们不同但相似。 c#名称空间的想法必须来自c ++名称空间。有人必须看到类似但不同的东西可以做什么,并且没有足够的想象力留给它自己的原始名称,如“ClassPath”,这将更有意义,因为它是一个通往课程的路径,而不是提供命名空格,其中每个空格可以具有相同的名称

我希望这有助于某人

我忘了说所有这些方式都是有效的,并且可以将前两个的适度使用合并到第三个中以创建一个有意义的库,即(不是很好的例子)

_INT::POINT2{}

_DOUBLE::POINT2{}

因此您可以使用

更改精度级别
#define PREC _DOUBLE 
// or #define PREC _INT 

然后为双精度POINT2

创建PREC :: POINT2的实例

使用c#或java命名空间

并不容易 显然,这只是一个例子。想一想用法如何阅读。

答案 7 :(得分:-1)

你过度使用它们(你将得不到任何回报)。

答案 8 :(得分:-1)

我有时会将深度名称空间声明为单独标题中的几个宏

<强> 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;

宏之后的冗余分号是为了避免额外的缩进。