C++ 命名空间,与 Java 包的比较
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2108172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ Namespaces, comparison to Java packages
提问by Mr. Boy
I've done a bunch of Java coding recently and have got used to very specific package naming systems, with deep nesting e.g. com.company.project.db
. This works fine in Java, AS3/Flex and C#. I've seen the same paradigm applied in C++ too, but I've also heard that it's bad to view C++ namespaces as direct counterparts to Java packages.
我最近完成了大量 Java 编码,并且已经习惯了非常具体的包命名系统,例如com.company.project.db
. 这在 Java、AS3/Flex 和 C# 中运行良好。我也看到了在 C++ 中应用的相同范例,但我也听说将 C++ 命名空间视为 Java 包的直接对应物是不好的。
Is that true, and why? How are namespaces/packages alike and different? What problems are likely to be seen if you do use deep nested namespaces?
这是真的吗,为什么?命名空间/包有何相似和不同之处?如果使用深层嵌套命名空间,可能会出现哪些问题?
采纳答案by philsquared
In C++ namespaces are just about partitioning the available names. Java packages are about modules. The naming hierarchy is just one aspect of it.
在 C++ 中,命名空间只是对可用名称进行分区。Java 包是关于模块的。命名层次结构只是其中的一个方面。
There's nothing wrong, per-se, with deeply nested namespaces in C++, except that they're not normally necessary as there's no module system behind them, and the extra layers just add noise. It's usually sufficient to have one or two levels of namespace, with the odd extra level for internal details (often just called Details).
C++ 中深度嵌套的命名空间本身并没有错,只是它们通常不是必需的,因为它们背后没有模块系统,而额外的层只会增加噪音。通常有一个或两个级别的命名空间就足够了,还有一个用于内部细节的奇怪的额外级别(通常称为细节)。
There are also extra rules to C++ namespaces that may catch you out if overused - such as argument-dependent-lookup, and the rules around resolving to parent levels. WRT the latter, take:
C++ 命名空间还有一些额外的规则,如果过度使用,可能会引起你的注意——例如参数依赖查找,以及关于解析到父级别的规则。WRT后者,取:
namespace a{ namespace b{ int x; } }
namespace b{ string x; }
namespace a
{
b::x = 42;
}
Is this legal? Is it obvious what's happening? You need to know the precendence of the namespace resolution to answer those questions.
这是合法的吗?发生的事情很明显吗?您需要知道命名空间解析的优先级才能回答这些问题。
回答by skaffman
Java packages are not nested, they're flat. Any apparent nesting is nothing more than a naming convention.
Java 包不是嵌套的,它们是扁平的。任何明显的嵌套只不过是一种命名约定。
For example, the package com.company.project.db
has no relation whatsoever to com.company.project
or com.company.project.db.x
. Code in com.company.project.db
has no more access to code in com.company.project.db.x
than would code in a.b.c
.
例如,包com.company.project.db
与com.company.project
或没有任何关系com.company.project.db.x
。代码输入com.company.project.db
没有com.company.project.db.x
比代码输入更多的代码访问权限a.b.c
。
回答by Charles Eli Cheese
You can have nested namespaces in C++.
您可以在 C++ 中嵌套命名空间。
They don't work the same as in java, though, obviously. Java packages are really much better defined and there is no real static init weirdness. With C++ namespaces are helpful but still have a fair bit of danger involved.
但是,很明显,它们与在 Java 中的工作方式不同。Java 包的定义确实要好得多,并且没有真正的静态 init 怪异之处。使用 C++ 命名空间是有帮助的,但仍然有相当多的危险。
回答by Charles Eli Cheese
In C++, the basic unit of design and implementation is the class, not the namespace. Namespaces were intended as a means of preventing name clashes in large libraries, not for expressing concepts.
在 C++ 中,设计和实现的基本单位是类,而不是命名空间。命名空间旨在防止大型库中的名称冲突,而不是用于表达概念。
Classes have several advantages over namespaces:
与命名空间相比,类有几个优点:
- they can have constructors and destructors
- they can have private members
- they cannot be re-opened
- 他们可以有构造函数和析构函数
- 他们可以有私人成员
- 它们不能重新打开
However, I would look twice at any deeply nested relationship. That is really not a good way of designing software, and leads to unreadable code, whether you juse classes or namespaces.
但是,我会仔细研究任何深度嵌套的关系。这真的不是设计软件的好方法,并且会导致不可读的代码,无论您使用类还是命名空间。
回答by Mr. Boy
I'll throw in a couple of things I've heard but don't know the truthfulness of, please help confirm/dispel them.
我将抛出一些我听说过但不知道真实性的事情,请帮助确认/消除它们。
C++ performance is (somehow) affected by long fully-specified method names e.g
namespace1::namespace2::namespace3::classX::method123()
You might hit a limit on allowed symbol length in the compiler/linker
C++ 性能(以某种方式)受长的完全指定的方法名称的影响,例如
namespace1::namespace2::namespace3::classX::method123()
您可能会遇到编译器/链接器中允许的符号长度限制
回答by SystematicFrank
I think there is something missing in the previous answers, and it is one of the reasons I really like C++.
我认为之前的答案中缺少一些东西,这也是我非常喜欢 C++ 的原因之一。
Imagine you are programming a graphical application and suddenly you realize that there is something common among all your widgets. You want all of them to have a new function. What do you do?
想象一下,您正在编写一个图形应用程序,突然您意识到您的所有小部件之间有一些共同点。您希望它们都具有新功能。你做什么工作?
1) Edit the base widget class? OK, but most likely you do not have access to it. Maybe there is a licensing problem that prevents you from doing your own modification. Even if you can just do it, if it is something that only makes sense for your project, the authors will not include it in their future release, and upgrading the toolkit will be more painful
1) 编辑基本小部件类?好的,但很可能您无权访问它。也许存在许可问题阻止您进行自己的修改。即使你能做到,如果它只对你的项目有意义,作者不会在他们未来的版本中包含它,升级工具包会更痛苦
2) Create an interface class / multi-inheritance? Depending on your existing code it will be more or less of a pain to update every single class related with a widget. Do this and your code will cost more to maintain because everyone defining a new class must know that they are suppose to inherit from your interface. Becoming dependent of other people discipline is really risky.
2)创建接口类/多继承?根据您现有的代码,更新与小部件相关的每个类或多或少会很痛苦。这样做会使您的代码维护成本更高,因为每个定义新类的人都必须知道他们应该从您的接口继承。依赖他人的纪律真的很危险。
The wonderful thing of C++ namespaces here is that you have an extra way to encapsulate stuffwithin an already existing system. Not only you can encapsulate within already existing libraries that you cannot edit, you can encapsulate similar concepts that you cannot easily insert into your hierarchy of classes/objects.
C++ 命名空间的奇妙之处在于,您有一种额外的方法可以将内容封装在现有系统中。您不仅可以将无法编辑的现有库封装到其中,还可以封装无法轻松插入到类/对象层次结构中的类似概念。
Java forces you to focus more on a pure OOP design. Sure that I am telling you might be a dirty hack and not elegant, but there are lots of lazy people programming who do not spend time fixing their designs.
Java 迫使您更多地关注纯 OOP 设计。当然,我告诉你可能是一个肮脏的黑客而不是优雅的,但是有很多懒惰的人编程不花时间修复他们的设计。
回答by Shital Shah
Here are some reasons why and how C++ namespaces are different than Java or C# namespaces.
以下是 C++ 命名空间与 Java 或 C# 命名空间不同的一些原因和方式。
Avoiding conflicts
避免冲突
In Java/C# languages, namespaces are intended to avoid conflicts between names in different parts of class libraries. You may have class called "Watcher" in 5 different places in namespace hierarchy in C#. In C++, if you have same named classes occurring in your library then you put inside another class instead of creating namespaces. Such nested classes are all fine and encouraged and in fact the syntax also treats as if class is a namespace using :: operator.
在 Java/C# 语言中,命名空间旨在避免类库不同部分中的名称之间的冲突。您可能在 C# 中命名空间层次结构的 5 个不同位置有名为“Watcher”的类。在 C++ 中,如果您的库中出现相同命名的类,那么您将放入另一个类中,而不是创建命名空间。这样的嵌套类都很好并且受到鼓励,实际上语法也将类视为使用 :: 运算符的命名空间。
How much nested namespaces should be?
应该有多少嵌套的命名空间?
Popular libraries like Boost, Eigen and of course, STL provides good examples. these libraries typically have pretty much everything stuffed in to one namespace like std::
or boost::
or eigen::
. Few components get their own namespace like std::ios
or boost:filesystem
. There is no consistent rules around when to use second level but it seems large or separately developed/maintained or optional components typically get their own namespaces. The third level is even more rare. Generally I use the structure company::project
and for large independently usable subsystem of projects company::project::component
.
像 Boost、Eigen 和 STL 这样的流行库提供了很好的例子。这些库通常将几乎所有内容都塞进一个命名空间中,例如std::
orboost::
或eigen::
。很少有组件像std::ios
or那样拥有自己的命名空间boost:filesystem
。关于何时使用第二级没有一致的规则,但似乎大型或单独开发/维护或可选组件通常有自己的命名空间。第三层更是难得一见。通常我使用结构company::project
和大型独立可用的项目子系统company::project::component
。
Avoiding conflicts in external libraries
避免外部库中的冲突
Now the big question: What if you get two libraries from two different people which has exact same namespaces and classes? This situation is fairly rare because most people tend to wrap their libraries at least in their project's name. Even if project names are same, its even rarer that you end up using libraries from both. However sometimes bad decisions are made for project names (ahm... "metro", "apollo" ...) or even namespaces are just not used at all. If that happens, you wrap #include for either or both libraries in to a namespace and conflict is resolved! This is one reason why people don't bother too much about conflicts because resolving them is trivial. If you follow the practice of using company::project
then conflicts become super rare.
现在最大的问题是:如果你从两个不同的人那里得到两个具有完全相同的命名空间和类的库怎么办?这种情况相当罕见,因为大多数人倾向于至少以他们的项目名称包装他们的库。即使项目名称相同,最终使用两者的库的情况也更少见。然而,有时对项目名称(ahm...“metro”、“apollo”...)做出错误的决定,甚至根本不使用命名空间。如果发生这种情况,请将其中一个或两个库的 #include 包装到命名空间中,冲突就解决了!这就是人们不会太在意冲突的原因之一,因为解决它们是微不足道的。如果您遵循使用的做法,company::project
那么冲突将变得非常罕见。
Differences in languages
语言差异
Although C++ provides using namespace
statement just like C#, its generally considered a bad practice to "import" everything in your own namespace. The reason for this is that a header can contain lots of "bad" stuff including redefining things that can totally surprise you. This is quite unlike C#/Java where you only get clean public interface when you do equivalent of using namespace
. (side note: in C++ you can achieve the same thing by using Pimpl pattern but its usually too much of extra plumbing and few libraries actually do it). So you almost never want to do using namespace
. Instead you do typedefs
(or using name =
) for what you actually want to use. This again makes deeply nested namespaces impractical to use.
尽管 C++ 提供using namespace
了与 C# 一样的语句,但通常认为将所有内容“导入”到您自己的命名空间中是一种不好的做法。这样做的原因是标题可能包含许多“坏”的东西,包括重新定义的东西,这些东西会让你大吃一惊。这与 C#/Java 完全不同,在 C#/Java 中,当您执行等效于using namespace
. (旁注:在 C++ 中,你可以通过使用 Pimpl 模式来实现同样的事情,但它通常有太多额外的管道,而很少有库真正做到这一点)。所以你几乎永远不想做using namespace
。相反,您为您真正想要使用的东西做typedefs
(或using name =
)。这再次使得深度嵌套的命名空间无法使用。
Organizing code
组织代码
In Java/C#, people tend to organize code in folders a lot. Typically as folder grows more than 20 or even 10 files, people would start thinking about folders. In C++, things are more diversebut for many large projects flatter directory structures are preferred. For example, standard library's std folderhas 53 files and Facebook's follyproject seems to go same route. I think one reason for this probably is the fact Java/C# folks use visual IDEs more and use mouse scrolls in folder navigation as opposed to console where you can use wild cards to find file in flat structure. Also C++ programmers absolutely don't shy away from putting multiple classes in single file and naming file as logical unit instead of same as class name unlike in C# or Java. This makes compilation faster which is very important for large projects. While there is no language-level requirement for having its own namespace for each folder many C++ developers prefers to assign its own namespace to each folder and keep folder hierarchy 2 or less levels deep.
在 Java/C# 中,人们倾向于在文件夹中组织代码。通常当文件夹增长超过 20 个甚至 10 个文件时,人们会开始考虑文件夹。在 C++ 中,事情更加多样化,但对于许多大型项目,更喜欢扁平的目录结构。例如,标准库的std 文件夹有 53 个文件,而 Facebook 的愚蠢项目似乎走相同的路线。我认为其中一个原因可能是 Java/C# 人们更多地使用可视化 IDE 并在文件夹导航中使用鼠标滚动,而不是在控制台中您可以使用通配符在平面结构中查找文件。此外,C++ 程序员绝对不会回避将多个类放在单个文件中并将文件命名为逻辑单元,而不是与 C# 或 Java 中的类名相同。这使得编译更快,这对于大型项目非常重要。虽然对于每个文件夹都有自己的命名空间没有语言级别的要求,但许多 C++ 开发人员更喜欢将自己的命名空间分配给每个文件夹,并将文件夹层次结构保持在 2 级或更低级别。
Possible exception
可能的异常
In C++ you can refer to A::B::C::D
as just C::D
if you are already inside A::B
. So if you have private code or less used classes that you want to push further down then you might do so while still keeping your own relative depth to 2 or so. In this case, you might also want to create folder for each level just so file locations are predictable. In general, there are no gold standards in this area but you do not want to go overboard with deeply nested namespaces mimicking C#/Java.
在 C++ 中,您可以参考,A::B::C::D
就像C::D
您已经在A::B
. 因此,如果您有私有代码或较少使用的类想要进一步向下推,那么您可以这样做,同时仍将自己的相对深度保持在 2 左右。在这种情况下,您可能还想为每个级别创建文件夹,以便可以预测文件位置。一般来说,这方面没有黄金标准,但您不想过度使用模仿 C#/Java 的深度嵌套命名空间。
Related
有关的