[英]C++ namespaces advice
我只是在自学 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++ 示例中看到大量使用名称空间的原因吗? 或者通常只有单个(非嵌套)命名空间?
更新
对于任何感兴趣的人, 这就是我最终解决这个问题的方式。
C++ 命名空间并不是一种设计机制——它们只是为了防止名称冲突。 在 99.99% 的情况下,您确实不想或不需要使用嵌套命名空间。
在 C++ 中正确使用命名空间的一个很好的例子是 C++ 标准库。 这个相当大的库中的所有内容都放在一个名为std 的命名空间中——没有尝试或需要将库分解成(例如)一个 I/O 子命名空间、一个数学子命名空间、一个容器子命名空间等等。
在 C++ 中建模的基本工具是类(在某种程度上是模板),而不是命名空间。 如果你觉得需要嵌套,你应该考虑使用嵌套类,它比命名空间有以下优点:
考虑到这些之后,如果您仍然希望使用嵌套命名空间,那么就这样做 - 以这种方式使用它们在技术上没有任何问题。
C++ 命名空间比以前的产品有了很大的改进(即根本没有命名空间)。 C# 命名空间扩展了这个概念并运行了它。 我建议您将命名空间保持在一个简单的平面结构中。
编辑您是否建议由于我在此处概述的缺点?
简单地说“是”。 C++ 命名空间的设计目的不是像在 C# 中那样帮助您划分逻辑和库。
C++ 命名空间的目的是阻止 C 开发人员在使用两个导出相同函数名称的第三方库时遇到名称冲突的现实问题。 C 开发人员对此有各种解决方法,但这可能会很痛苦。
这个想法是 STL 等具有std::
命名空间,“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;
};
}
}
}
使用这种风格在开始时需要一些纪律,但对我来说这是最好的妥协。
从 C++17 开始,您可以使用问题作者提出的语法声明命名空间。
namespace A::B::C { ... }
嵌套命名空间定义:
namespace A::B::C { ... }
等价于namespace A { namespace B { namespace C { ... } } }
。
至少作为一个小帮助,在某些情况下你可以这样做:
namespace foo = A::B::C::D;
然后将 A::B::C::D 引用为 foo。 但仅在某些情况下。
您可以跳过缩进。 我经常写
namespace myLib { namespace details {
/* source code */
} } /* myLib::details */
C++ 源代码最终被编译成二进制,不像 C#/Java 停留在二进制中。 因此,namespace 只是为变量命名冲突提供了一个很好的解决方案。 它不适用于类层次结构。
我经常在代码中保留一两个命名空间级别。
首先,您可以避免名称空间缩进,因为没有理由这样做。
在示例中使用命名空间不会显示命名空间的威力。 而对我而言,他们的力量正在将领域区域一分为二。 将实用程序类与业务类分开。
只是不要在一个 .h 文件中混合不同的命名空间层次结构。 命名空间是对函数声明接口的一种额外注释。 查看命名空间和类名应该可以解释很多东西。
namespace product
{
namespace DAO
{
class Entity
{
};
我发现你可以像这样模仿 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 命名空间做这件事不是一件容易的事
显然这只是一个例子。 想想用法如何阅读。
您过度使用它们(并且您将一无所获)。
我有时将深层命名空间声明为单独的标头中的几个宏
命名空间.h
#define NAMESPACE_TIER1_TIER2_TIER3 \
namespace tier1 { \
namespace tier2 { \
namespace tier3 {
#define END_NAMESPACE_TIER1_TIER2_TIER3 }}}
要在其他地方使用它:
另一个文件.h
#include "./namespace.h"
NAMESPACE_TIER1_TIER2_TIER3;
/* Code here */
END_NAMESPACE_TIER1_TIER2_TIER3;
宏后面多余的分号是为了避免额外的缩进。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.