C ++命名空间的build议
我只是教自己的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
对于任何有兴趣的人来说, 这就是我最终解决这个问题的方法。
C ++命名空间并不打算成为一种devise机制 – 它们只是为了防止名称冲突。 在99.99%的情况下,你真的不想或者不需要使用嵌套的命名空间。
在C ++中正确使用名称空间的一个很好的例子就是C ++标准库。 这个相当大的库中的所有东西都放在一个名为std的单一名称空间中 – 没有任何尝试或需要将库分成(例如)一个I / O子名称空间,一个math子名称空间,一个容器子名称空间等等
在C ++中build模的基本工具是类(在某种程度上是模板),而不是命名空间。 如果你觉得需要嵌套,你应该考虑使用嵌套类,它比名称空间有以下优点:
- 他们有方法
- 他们可以控制访问
- 他们不能重新开放
考虑过这些之后,如果你仍然希望使用嵌套命名空间的话,那么以这种方式使用它们没有任何技术上的错误。
C ++命名空间比以前的产品有了很大的改进(即根本没有命名空间)。 C#命名空间已经扩展了这个概念并且运行了它。 我build议你保持你的命名空间在一个简单的平面结构。
编辑 你是否build议,由于我在这里概述的短缺?
只是“是”。 C ++命名空间的devise不是为了帮助您像在C#中那样分割逻辑和库。
C ++命名空间的目的是停止C开发人员遇到的现实世界问题,在使用两个导出相同函数名的第三方库时,他们遇到名称冲突。 C开发人员对此有不同的解决方法,但这可能是一个严重的问题。
这个想法是,STL等有std::
namespace,由“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; }; } } }
使用这种风格在开始时需要一点纪律,但这对我来说是最好的折衷。
至less作为一个小小的帮助,在某些情况下,你可以做到这一点:
namespace foo = A::B::C::D;
然后引用A :: B :: C :: D作为foo。 但只在某些情况下。
首先你可以避免命名空间缩进,因为没有理由。
在示例中使用名称空间不会显示名称空间的权力。 而他们的权力,就是把领域划分到另一个领域。 将公用事业类别与业务类别划分开来。
只要不在一个.h文件中混合不同的命名空间层次结构。 命名空间对函数声明的接口是一种额外的注释。 看名字空间和类名应该解释很多东西。
namespace product { namespace DAO { class Entity { };
您可以跳过缩进。 我经常写
namespace myLib { namespace details { /* source code */ }; }; /* myLib::details */
C ++源代码最终被编译成二进制文件,不像C#/ Java那样保留在二进制文件中。 因此,名称空间只是为variables命名冲突提供了一个很好的解决scheme。 它不适用于类层次结构。
我经常在代码中保留一个或两个名称空间级别。
我发现你可以像这样模仿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 { }
但是代码似乎不是很整齐。 而且我期望有长时间的使用
将类似的functionembedded到类中更好
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”,这将是更有意义的,作为一个类的path,而不是提供命名每个空间可以具有相同名称的空间
我希望这可以帮助别人
我忘了说,所有这些方法是有效的,适度使用前两个可以合并到第三个创build一个图书馆是有道理的,(不是很好的例子)
_INT::POINT2{}
和
_DOUBLE::POINT2{}
所以你可以通过使用改变精度水平
#define PREC _DOUBLE // or #define PREC _INT
然后为双精度POINT2创build一个PREC :: POINT2的实例
这对于使用c#或java命名空间并不容易
显然这只是一个例子。 考虑如何使用阅读。
你过度使用它们(你将不会得到任何回报)。
我有时在一个单独的头文件中将深名称空间声明为一对macros
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;
macros之后的冗余分号是为了避免额外的缩进。