类和命名空间?
这个问题是关于我看到自己越来越多地使用的一种模式:同时拥有相关概念的类和命名空间。我认为这主要是由 C++ 语言工件推动的,但并非完全如此。
我想最重要的问题是:这是个好主意吗?同时拥有相关概念的类和命名空间?
低级问题:
做这个的最好方式是什么?
嵌套在命名空间中的类?:
namespace Foo_Namespace {
class Foo_Class {
...
};
}
还是分开,对等,类和命名空间?:
class Foo_Class {
...
};
namespace Foo_Namespace {
// non-class free functions, etc.
}
我必须承认我倾向于将类嵌套在命名空间中。即使它导致丑陋的名字。但即使我这样做,我应该使用什么命名约定:
以下内容太长,导致名称非常难看 Foo_Namespace::Foo_Class
namespace Foo_Namespace {
class Foo_Class {
...
};
}
不必在名称中使用任何后缀或指示符:
namespace Foo {
class Foo {
...
};
}
但是后来我发现自己不确定,当我查看 Foo::bar() 时,它是命名空间 ::Foo 中的自由函数 bar,即 ::Foo::bar(),还是命名空间中类 Foo 中的成员函数::Foo::Foo::bar()。
像 ::Foo::Foo::bar 这样的名字仍然不是,嗯,很好。
目前我正在做
不必在名称中使用任何后缀或指示符:
namespace Foo_ns {
class Foo {
...
};
}
主要是因为我通常先创建类,然后才意识到命名空间会很好。
我想知道我是否应该恢复多年来未使用的命名约定:_c 用于类,_ns 用于命名空间:
namespace Foo_ns {
class Foo_c {
...
};
}
细节:
我不会重复我上面所说的,但我会补充一点。
除了类之外,我知道使用命名空间的最实际原因是您可以在命名空间中对自由函数进行前向声明,但不允许对类的某些方法进行前向声明。即对于一个类,您必须全部或全部声明它。而对于一般的自由函数,特别是命名空间中的自由函数,您可以将其声明为零碎的。部件可以在不同的头文件中声明。您可以只为一个或两个函数使用前向声明,而不是为一个庞大的类#include 一个庞大的仅标头库。等等。
(例如,请参阅http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Forward_Declarations,尽管 Google 完全反对前向声明而不是包含标题。)
另一个原因是命名空间允许类本身保持较小。
类的最大优点是类可以传递给模板,而命名空间不能。
我更喜欢将类嵌套在命名空间 Foo_ns/Foo_ns::Foo_c 中,而不是将它们作为对等的 Foo_ns/Foo_c,因为通常一个类需要辅助类,例如 Foo_ns/Foo_ns::Foo_c/Foo_ns::Foo_Helper_c。如果类和命名空间是对等的,那么拥有 Foo_ns/Foo_c 而拥有 Foo_ns::Foo_Helper_c 似乎很奇怪。
我喜欢命名空间,因为我同意 Andrei Alexandresciu: http: //laser.inf.ethz.ch/2012/slides/Alexandrescu/1-C++%20course%20parts%201%20and%202.pdf
Class methods vs. free functions
• Conventional wisdom: methods are cool, free functions are so 1960s
• Yet:
◦ Free functions improve encapsulation over methods
◦ Free functions may be more general
◦ Free functions decouple better
◦ Free functions support conversions on their left-hand argument
Surprising fact #2
Making a function a method should be
your last, not first, choice
(c) 2012– Andrei Alexandrescu. 32 / 59
创建自由函数比创建类中的方法更好。
但有时只需要使用类——例如用于模板。
命名约定明智
我过去使用过 Foo_ns / Foo_ns::Foo_c
我现在正在使用 Foo_ns / Foo_ns::Foo
(顺便说一句,我倾向于使用 Class_Names_With_Underscores_and_Initial_Caps,而不是 CamelCase。)
如果有意义,我可能会省略命名空间上的 _ns 后缀 - 例如,命名空间和类不需要具有相同的名称。
我不喜欢让他们有相同的名字。考虑命名空间 foo 中类 Foo 的构造函数:
::Foo::Foo::Foo() 与 ::Foo_ns::Foo::Foo()
后者也好不了多少,但也少了一些混乱。
我认为我通常自己创建类,而不将其嵌套在命名空间中。事实上,在我意识到嵌套在命名空间中的类会更好之前,我可能会添加一些静态方法。到那个阶段,重构可能会很痛苦,有时我最终会创建转发函数,从类静态方法转发到命名空间中的自由函数,反之亦然。这让我很遗憾机器人从第 1 步开始就跳到带有命名空间的类。
结论
我当前的 BKM 是 Foo_ns / Foo_ns::Foo,即
namespace Foo_ns {
class Foo {
...
};
}
我会很感激任何建议,任何改进。
还是我只是因为这样做而崩溃?