简体   繁体   English

C++ 命名空间建议

[英]C++ namespaces advice

I'm just teaching myself C++ namespaces (coming from a C# background) and I'm really starting to think that even with all the things that C++ does better than most other languages, nested namespaces isn't one of them!我只是在自学 C++ 命名空间(来自 C# 背景),我真的开始认为即使 C++ 比大多数其他语言做得更好,嵌套命名空间也不是其中之一!

Am I right in thinking that in order to declare some nested namespaces I have to do the following:我是否认为为了声明一些嵌套的命名空间,我必须执行以下操作:

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

As opposed to:与之相反:

namespace tier1::tier2::tier3
{
}

à la C#? à la C#?

This becomes even more demented when I need to forward declare:当我需要转发声明时,这变得更加疯狂:

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

Bearing in mind that a typical system that I develop consists of:请记住,我开发的典型系统包括:

MyCompany::MySolution::MyProject::System::[PossibleSections]::Type

Is this why you don't tend to see much use of namespaces in C++ examples?这就是为什么您不倾向于在 C++ 示例中看到大量使用名称空间的原因吗? Or usually only single (not nested) namespaces?或者通常只有单个(非嵌套)命名空间?

UPDATE更新

For anyone interested, this is how I ended up tackling this issue.对于任何感兴趣的人, 这就是我最终解决这个问题的方式。

C++ namespaces were not intended to be a design mechanism - they are there simply to prevent name clashes. C++ 命名空间并不是一种设计机制——它们只是为了防止名称冲突。 You really don't want or need to use nested namespaces in 99.99% of situations.在 99.99% 的情况下,您确实不想或不需要使用嵌套命名空间。

A good example of the correct use of namespaces in C++ is the C++ Standard Library.在 C++ 中正确使用命名空间的一个很好的例子是 C++ 标准库。 Everything in this quite large library is placed in a single namespace called std - there is no attempt or need to break the library up into (for example) an I/O sub-namespace, a math sub-namespace, a container sub-namespace etc.这个相当大的库中的所有内容都放在一个名为std 的命名空间中——没有尝试或需要将库分解成(例如)一个 I/O 子命名空间、一个数学子命名空间、一个容器子命名空间等等。

The basic tool for modelling in C++ is the class (and to some extent the template), not the namespace.在 C++ 中建模的基本工具是类(在某种程度上是模板),而不是命名空间。 If you feel the need for nesting, you should consider using nested classes, which have the following advantages over namespaces:如果你觉得需要嵌套,你应该考虑使用嵌套类,它比命名空间有以下优点:

  • they have methods他们有方法
  • they can control access他们可以控制访问
  • they cannot be re-opened它们不能重新打开

Having considered these, if you still wish to use nested namespaces by all means do so - there is nothing technically wrong with using them in this way.考虑到这些之后,如果您仍然希望使用嵌套命名空间,那么就这样做 - 以这种方式使用它们在技术上没有任何问题。

C++ namespaces were a vast improvement over the previous offering (ie no namespaces at all). C++ 命名空间比以前的产品有了很大的改进(即根本没有命名空间)。 C# namespaces have extended the concept and ran with it. C# 命名空间扩展了这个概念并运行了它。 I would advise you to keep your namespaces in a simple flat structure.我建议您将命名空间保持在一个简单的平面结构中。

EDIT Do you advise that due to the short comings i've outlined here?编辑您是否建议由于我在此处概述的缺点?

Simply "Yes".简单地说“是”。 C++ namespaces weren't designed to help you partition your logic & libraries the way they do in C#. C++ 命名空间的设计目的不是像在 C# 中那样帮助您划分逻辑和库。

The purpose of C++ namespaces is to stop the real world problem encountered by C developers, where they experience name collisions when using two third party libs that export the same function name(s). C++ 命名空间的目的是阻止 C 开发人员在使用两个导出相同函数名称的第三方库时遇到名称冲突的现实问题。 C developers had various workarounds for it, but it could be a serious pain. C 开发人员对此有各种解决方法,但这可能会很痛苦。

The idea was that the STL etc has the std:: namespace, libs provided by "XYZ Corp" would have an xyz:: namespace, you working for "ABC corp" would put all your stuff in a single abc:: namespace.这个想法是 STL 等具有std::命名空间,“XYZ Corp”提供的库将具有xyz::命名空间,您为“ABC corp”工作会将所有内容放在一个abc::命名空间中。

what I do when forward declaring looks like this:前向声明时我所做的如下所示:

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

My forward declarations are collapsed into single line.我的前向声明被折叠成一行。 Readability of forward declaration is sacrificed in return for the readability of the rest of code.牺牲前向声明的可读性以换取其余代码的可读性。 And for definitions I don't use indentations either:对于定义,我也不使用缩进:

 namespace abc {
 namespace sub {
 namespace subsub {
 
 class MyClass 
 {
    public:
       MyClass();

       void normalIntendationsHere() const;
 };

 }
 }
 }

Using this style requires a bit of discipline at the beginning, but it's the best compromise for me.使用这种风格在开始时需要一些纪律,但对我来说这是最好的妥协。


Since C++17 you can declare namespace with a syntax proposed by the author of the question.从 C++17 开始,您可以使用问题作者提出的语法声明命名空间。

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

nested namespace definition: namespace A::B::C { ... } is equivalent to namespace A { namespace B { namespace C { ... } } } .嵌套命名空间定义: namespace A::B::C { ... }等价于namespace A { namespace B { namespace C { ... } } }

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

Atleast as a small help, in some cases you can do this:至少作为一个小帮助,在某些情况下你可以这样做:

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

And then reference A::B::C::D as foo.然后将 A::B::C::D 引用为 foo。 But only in some cases.但仅在某些情况下。

You can skip indentation.您可以跳过缩进。 I often write我经常写

namespace myLib { namespace details {

/* source code */

} } /* myLib::details */

C++ source code is eventually compiled into binary, unlike C#/Java which stays in the binary. C++ 源代码最终被编译成二进制,不像 C#/Java 停留在二进制中。 Therefore, namespace just provides a fine solution for variable naming conflict.因此,namespace 只是为变量命名冲突提供了一个很好的解决方案。 It is not intended for class hierarchy.它不适用于类层次结构。

I often keep one or two namespace levels in the code.我经常在代码中保留一两个命名空间级别。

First of all you can avoid namespace indentation, because there is no reason for that.首先,您可以避免名称空间缩进,因为没有理由这样做。

Using namespaces in the examples won't show namespaces power.在示例中使用命名空间不会显示命名空间的威力。 And their power as for me is dividing Domain areas one from another.而对我而言,他们的力量正在将领域区域一分为二。 Divide utility classes from the business ones.将实用程序类与业务类分开。

Just don't mix different namespace hierarchies in the one .h file.只是不要在一个 .h 文件中混合不同的命名空间层次结构。 Namespaces are kind of extra comment for your interface of functions declaration.命名空间是对函数声明接口的一种额外注释。 Looking on namespaces and the class names should explain a lot of stuff.查看命名空间和类名应该可以解释很多东西。

namespace product
{
namespace DAO
{

class Entity
{
};

I have found that you can sort of mimic the c# namespace like this;我发现你可以像这样模仿 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
{
}

But code doesn't seem to be very tidy.但是代码好像不是很整齐。 and i would expect to have long winded usage我希望能长期使用

It is better to nest as much functionality into classes something like最好将尽可能多的功能嵌套到类中,例如

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*/

And that is still a little bit long winded.这仍然有点啰嗦。 but does feel a little bit OO.但确实感觉有点OO。

And hears how it seems best done并听到它似乎做得最好

namespace ABC
{
    class POINT2{};
    class Complex:POINT2{};
    Complex ComplexFromPOINT2(POINT2 p){return new Complex();}
    POINT2 POINT2FromComplex(Complex){return new POINT2();}
}

hears how usages would look听听用法的样子

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());
}

its been interesting to find out why i never used c++ namespaces like i would with c#.找出为什么我从未像使用 c# 那样使用 c++ 命名空间的原因很有趣。 It would be too long winded, and would never work the same way as c# namespaces.它太冗长了,并且永远不会像 c# 命名空间那样工作。

the best use for namespaces in c++ is to stop say my super cout function (that dings every time its called) from getting mixed up with the std::cout function (which is far less impressive). C++ 中命名空间的最佳用途是停止说我的超级 cout 函数(每次调用时都会响起)与 std::cout 函数(这远没有那么令人印象深刻)混淆。

Just because c# and c++ have namespaces, it doesn't mean that namespace means the same thing.仅仅因为 c# 和 c++ 具有命名空间,并不意味着命名空间的含义相同。 they are different but similar.它们不同但相似。 The idea for c# namespaces must have come from c++ namespaces. c# 命名空间的想法一定来自 c++ 命名空间。 somebody must have seen what a similar but different thing could do, and didn't have enough imagination power left to give it its own original name like "ClassPath" which would kind of make more sense as its a path to classes rather than for providing naming spaces where each space can have the same names有人一定已经看到了一个相似但不同的东西可以做什么,并且没有足够的想象力来给它自己的原始名称,比如“ClassPath”,这更有意义,因为它是通往类的路径而不是提供命名空间,其中每个空间可以具有相同的名称

I hope this helps someone我希望这可以帮助别人

I forgot to say That all of these ways are valid, and moderate use of the first two can be incorporated into the the third to create a library that makes sense ie(not great example)我忘了说所有这些方法都是有效的,适度使用前两种可以合并到第三种中,以创建一个有意义的库即(不是很好的例子)

_INT::POINT2{}

and

_DOUBLE::POINT2{}

so you can change the precision level by using所以你可以通过使用改变精度级别

#define PREC _DOUBLE 
// or #define PREC _INT 

and then creating an instance of PREC::POINT2 for double precision POINT2然后为双精度 POINT2 创建一个 PREC::POINT2 实例

That is not an easy thing to do with c# or java namespaces用 c# 或 java 命名空间做这件事不是一件容易的事

obviously that's just one example.显然这只是一个例子。 Think about how the usage read.想想用法如何阅读。

您过度使用它们(并且您将一无所获)。

I sometimes declare deep namespaces as a couple of macros in a separate header我有时将深层命名空间声明为单独的标头中的几个宏

namespace.h命名空间.h

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

#define END_NAMESPACE_TIER1_TIER2_TIER3 }}}

To use it somewhere else:要在其他地方使用它:

anotherfile.h另一个文件.h

#include "./namespace.h"

NAMESPACE_TIER1_TIER2_TIER3;

/* Code here */

END_NAMESPACE_TIER1_TIER2_TIER3;

The redundant semicolons after the macro are to avoid extra indentation.宏后面多余的分号是为了避免额外的缩进。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM