我有Java背景,使用的是包,而不是名称空间。我习惯于将一起工作以形成完整对象的类放入包中,然后从该包中重用它们。但是现在我在用c++工作。
在c++中如何使用名称空间?您是为整个应用程序创建单个名称空间,还是为主要组件创建名称空间?如果是,如何从其他名称空间中的类创建对象?
我有Java背景,使用的是包,而不是名称空间。我习惯于将一起工作以形成完整对象的类放入包中,然后从该包中重用它们。但是现在我在用c++工作。
在c++中如何使用名称空间?您是为整个应用程序创建单个名称空间,还是为主要组件创建名称空间?如果是,如何从其他名称空间中的类创建对象?
当前回答
一般来说,如果我认为一段代码可能与其他库有函数或类型名称冲突,我会为它创建一个名称空间。它也有助于品牌代码,ala boost::。
其他回答
不要相信每个人都说名称空间只是名称空间。
它们很重要,因为它们被编译器用来应用接口原则。基本上,可以用一个例子来解释:
namespace ns {
class A
{
};
void print(A a)
{
}
}
如果你想打印一个A对象,代码将是这样的:
ns::A a;
print(a);
注意,在调用函数时没有显式地提到名称空间。这是接口原则:c++将一个以类型作为参数的函数视为该类型接口的一部分,因此不需要指定命名空间,因为形参已经隐含了命名空间。
为什么这个原则很重要呢?假设类A的作者没有为这个类提供print()函数。你必须自己提供一份。作为一名优秀的程序员,您将在自己的名称空间中定义这个函数,或者可能在全局名称空间中定义。
namespace ns {
class A
{
};
}
void print(A a)
{
}
你的代码可以在任何你想要的地方调用print(a)函数。现在想象一下,多年以后,作者决定提供一个print()函数,它比你的更好,因为他知道他的类的内部结构,并且可以提供一个比你的更好的版本。
然后,c++作者决定使用他的print()函数版本,而不是在另一个名称空间中提供的函数,以尊重接口原则。print()函数的“升级”应该尽可能简单,这意味着您不必更改对print()函数的每次调用。这就是为什么在c++中不需要指定命名空间就可以调用“接口函数”(与类在同一命名空间中的函数)。
这就是为什么在使用c++名称空间时应该将其视为“接口”,并记住接口原则。
如果你想要更好地解释这种行为,你可以参考Herb Sutter的《例外c++》这本书
命名空间本质上是包。它们可以这样使用:
namespace MyNamespace
{
class MyClass
{
};
}
然后在代码中:
MyNamespace::MyClass* pClass = new MyNamespace::MyClass();
或者,如果你想总是使用一个特定的名称空间,你可以这样做:
using namespace MyNamespace;
MyClass* pClass = new MyClass();
编辑:按照bernhardrusch所说,我倾向于不使用“使用名称空间x”语法,我通常在实例化对象时显式指定名称空间(即我展示的第一个示例)。
正如下面所要求的,您可以使用任意数量的名称空间。
另外,请注意,您可以添加到名称空间。举个例子就更清楚了,我的意思是你可以有:
namespace MyNamespace
{
double square(double x) { return x * x; }
}
在文件square.h中,和
namespace MyNamespace
{
double cube(double x) { return x * x * x; }
}
在文件cube.h中。这定义了一个单独的名称空间MyNamespace(也就是说,您可以跨多个文件定义一个单独的名称空间)。
java和c++的另一个区别是,在c++中,名称空间层次结构不需要调整文件系统布局。因此,我倾向于将整个可重用库放在一个单独的命名空间中,并将库中的子系统放在子目录中:
#include "lib/module1.h"
#include "lib/module2.h"
lib::class1 *v = new lib::class1();
如果存在名称冲突的可能性,我只会将子系统放在嵌套的名称空间中。
我在其他答案中没有看到任何提及,所以这里是我的2美分:
在“使用名称空间”主题上,一个有用的语句是名称空间别名,允许您“重命名”名称空间,通常是给它一个更短的名称。例如,不要:
Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::TheClassName foo;
Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::AnotherClassName bar;
你可以这样写:
namespace Shorter = Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally;
Shorter::TheClassName foo;
Shorter::AnotherClassName bar;