C + + 名称空间建议

我只是在自学 C + + 名称空间(来自 C # 背景) ,而且我真的开始认为,即使 C + + 做的所有事情都比大多数其他语言好,嵌套名称空间也不在其中!

为了声明一些嵌套的名称空间,我必须执行以下操作,这种想法是正确的吗:

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

而不是:

namespace tier1::tier2::tier3
{
}

在 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 + + 示例中不常使用名称空间的原因吗?或者通常只有单个(不是嵌套的)名称空间?

更新

对于任何感兴趣的人,这就是我的下场解决这个问题。

46380 次浏览

C + + 名称空间比之前的产品有了很大的改进(即根本没有名称空间)。C # 名称空间已经扩展了这个概念并运行它。我建议您将名称空间保持在一个简单的平面结构中。

由于我在这里列出的缺点,你是否建议这样做?

C + + 名称空间的设计并不是为了像 C # 那样帮助你划分逻辑和库。

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

这个想法是,STL 等有 std::名称空间,由“ XYZ 公司”提供的库将有一个 xyz::名称空间,你为“ ABC 公司”工作将把 所有你的东西在一个单一的 abc::名称空间。

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

在示例中使用名称空间并不能显示名称空间的威力。对我来说,他们的力量就是把领域从一个区域划分到另一个区域。将实用程序类与业务类分开。

只是不要将不同的名称空间层次结构混合在一起。H 档案。名称空间是函数声明接口的额外注释。查看名称空间和类名应该可以解释很多东西。

namespace product
{
namespace DAO
{


class Entity
{
};

C + + 名称空间并不打算成为一种设计机制——它们的存在只是为了防止名称冲突。在99.99% 的情况下,您确实不希望或不需要使用嵌套名称空间。

在 C + + 中正确使用名称空间的一个很好的例子就是 C++标准程式库。这个相当大的库中的所有东西都放在一个名为 性病的单一名称空间中——没有尝试或需要将库分解为(例如)一个 I/O 子名称空间、一个数学子名称空间、一个容器子名称空间等。

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

  • 他们有办法
  • 他们可以控制权限
  • 它们不能被重新打开

考虑过这些之后,如果您仍然希望使用嵌套名称空间,那么请务必这样做——以这种方式使用它们在技术上没有什么错误。

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

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

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

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

我在向前声明的时候是这样的:

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

我的转发声明被压缩成一行。前向声明的可读性被牺牲,以换取其余代码的可读性。对于定义,我也不使用缩进:

 namespace abc {
namespace sub {
namespace subsub {
 

class MyClass
{
public:
MyClass();


void normalIntendationsHere() const;
};


}
}
}

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


因为 C + + 17可以使用问题作者提出的语法声明名称空间。

namespace A::B::C { ... }

嵌套名称空间定义: namespace A::B::C { ... }是等效的 到 namespace A { namespace B { namespace C { ... } } }

Https://en.cppreference.com/w/cpp/language/namespace

你可以跳过缩进,我经常写作

namespace myLib { namespace details {


/* source code */


} } /* myLib::details */

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

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

我有时将深层名称空间声明为单独标头中的两个宏

H

#define NAMESPACE_TIER1_TIER2_TIER3 \
namespace tier1 { \
namespace tier2 { \
namespace tier3 {


#define END_NAMESPACE_TIER1_TIER2_TIER3 }}}

在其他地方使用:

另一份文件

#include "./namespace.h"


NAMESPACE_TIER1_TIER2_TIER3;


/* Code here */


END_NAMESPACE_TIER1_TIER2_TIER3;

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

我发现可以这样模仿 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 + + 中名称空间的最佳用途是停止使用我的 super cout 函数(每次调用它时都会叮一声) ,以免与 std: : cout 函数混淆(这一点远没有那么令人印象深刻)。

仅仅因为 c # 和 c + + 有名称空间,并不意味着名称空间意味着同样的事情。它们虽然不同,但是很相似。C # 名称空间的想法一定来自 c + + 名称空间。一定有人看到了一个类似但不同的东西能做什么,而且没有足够的想象力给它自己的原始名称,像“ ClassPath”,这将更有意义,因为它是一个类的路径,而不是提供命名空间,每个空间可以有相同的名称

我希望这能帮到别人

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

_INT::POINT2{}

还有

_DOUBLE::POINT2{}

所以您可以通过使用

#define PREC _DOUBLE
// or #define PREC _INT

然后为双精度 POINT2创建 PREC: : POINT2的实例

使用 c # 或 java 名称空间做到这一点并不容易

很明显,这只是一个例子。想想这个用法是如何解读的。