【问题标题】:Why namespace is needed in a header file?为什么头文件中需要命名空间?
【发布时间】:2013-02-26 13:35:08
【问题描述】:

我熟悉以下命名空间的使用。

在头文件中(例如people.h)我描述了一个名字空间的接口。例如:

namespace people{
   int getAge(str Name);
   void setName(str Name);
}

然后在people.cpp我从空间名称定义方法:

#include "people.h"
int people::getAge(str Name) {
   something_1;
   something_2;
}

void people::setName(str Name) {
   something_1;
}

但是,在我拥有的头文件中,我看到除了namespace people,还有其他命名空间的接口(例如namespace dogs)。而这些命名空间并没有在people.cpp 文件中定义。

所以,我假设(由于某些奇怪的原因)namespace dogs 的接口被放入people.h,然后名称空间 dog 被定义在“dogs.cpp”文件中。因此,换句话说,我假设在两个不同的 cpp 文件中定义了两个不同的名称空间,但它们的接口在一个头文件中描述。但是,这个假设似乎是错误的,因为我发现有很多头文件声明了“命名空间狗”。

所以,我假设 2people.h" 文件中的 namespace dogs 有另一个功能,但我不知道它是什么功能。有人可以帮我吗?

添加

我试图理解的代码不是我写的,它运行良好。所以,这应该是有道理的。可能是我不够清楚。所以,我试着举个例子:

在头文件 (people.h) 我有:

namespace etet
{
    class date;
}

namespace xsystem{
    class estimation_module;
}

namespace people {
   a_lot_of_different_stuff;
}

然后people.cpp 定义了属于人名空间的所有方法。

【问题讨论】:

  • 我什至不知道你能做到。
  • 在不知道使用这个狗命名空间的代码的情况下,我们只能推测。
  • I assumed that two different name spaces are defined in two different cpp files but their interface is described in one header file. 这听起来不错。
  • 这没有意义......
  • 我的猜测是您正面临一些简单的前向声明(people.h 需要来自 dogs 命名空间的某些类型,但不包括它们的完整定义以减少标头之间的依赖关系),但没有更精确的代码,很难说。

标签: c++ interface namespaces header-files


【解决方案1】:

“命名空间接口”是一个误导性概念。命名空间只是在一个姓氏下组合在一起的一堆名字(比如你​​和你的兄弟姐妹)。它没有“interface”,因为没有命名空间“obejct”。

#include "people.h"
int people::getAge(str Name) {
   something_1;
   something_2;
}

void people::setName(str Name) {
   something_1;
}

完全等同于

#include "people.h"
namespace people
{
  int getAge(str Name) {
     something_1;
     something_2;
  }

  void setName(str Name) {
     something_1;
  }
}

这可能是更熟悉的,也可能不是。 标头声明了 cpp 中不存在的函数这一事实,仅意味着它们可能存在于另一个中。

关于namespace name { ..... } 声明可以在许多文件中重复的事实,每个文件都包含各种功能是完全正常的,因为namespace 关键字不声明对象。它只是分组名称。而且 - 事实上 - 说命名空间是“声明的”是一种常见的语言滥用。声明的是命名空间的名称。

并且在不同地方声明的不同名称可以属于同一个组。这并没有什么神秘之处。

你的词典让我觉得你把 namespaces 与 classes 和 structs 混淆了

添加:

经过您的澄清,a_lot_of_different_stuff 似乎包含使用 etet::datexsystem::estimation_module; 的声明

编译器必须知道这些名称(并且只有名称),但标头不能递归地包含各自的标头,因为它们很可能已经包含 people.h

一个典型的“curculare reference”问题,如here,但涉及不同的命名空间。

【讨论】:

  • 你是对的。 a_lot_of_different_stuff 使用 etet::datexsystem::estimation_module。因此,我认为这就是为什么头文件中存在相应的 nane 空格的原因。但我不完全理解为什么我们不能包含这两个名称空间的标题(etetxsystem)。你说得对吗,你说我们不能包含这两个名称空间的标题,因为这两个标题已经包含 people.h 所以,我们可以得到一个“循环”包含?
  • @Roman:是的,那是我的hypotesys。但也可能是这些标头可能很长,而 people.h 所需要的只是这两个名称,因此它们复制了前向声明。您可以在标准库中找到类似的行为:想想<iosfowd> 标头:它包含<ios> 中定义的类的前向声明,对于所有情况,只需要名称,不需要所有细节。
【解决方案2】:

您混淆了命名空间和类。通常,类定义出现在头文件(.h)中,其成员函数的实现出现在相应的实现文件(.cpp)中。

命名空间与class 的工作方式不同。如果在多个翻译单元中定义了class,则它在所有翻译单元中必须具有完全相同的标记。你甚至不能对成员重新排序,即使它会产生完全相同的类。使用上面描述的头文件很容易满足这个要求。每个需要类foo 的翻译单元都包含foo.h 的内容,因为它们在需要时会使用#include "foo.h"。当然,它们都包含完全相同的foo 定义,因为它们都包含foo.h

但是,这与命名空间非常不同。命名空间可以在相同和不同的翻译单元中多次引入,而不是每次都是相同的标记。这样的事情完全没问题:

namespace bar {
  void baz();
  struct x;
}
// some stuff
namespace bar {
  void do_something(x);
}

namespace bar 的每次出现都会向该命名空间引入一些声明。

您通常会在同一个命名空间中定义许多类。这些类的每个标头都将执行 namespace whatever { ... } 并将类定义引入该命名空间。

有时您甚至希望在单个头文件中将内容引入多个命名空间或嵌套命名空间。没有什么可以阻止你这样做。这样做的一种可能情况是,如果您想从另一个命名空间转发声明某些内容。假设您在people.h 中定义了一个类,如下所示:

namespace people {
  class person {
    dogs::dog* pet_dog;
  };
}

现在,这个class 需要知道dogs 命名空间中的dog 类型。一种方法是#include "dogs.h"。但是,由于pet_dog 只是一个指针,我们可以处理不完整的类型,所以我们可以像这样转发声明dog

namespace dogs {
  class dog;
}

namespace people {
  class person {
    dogs::dog* pet_dog;
  };
}

【讨论】:

  • 我知道类和命名空间的区别。我只是说,在头文件中,我看到了一个名称空间的声明,其中包含属于该名称空间的所有方法的描述(即,对于每个方法,它的返回类型和变量类型都给出了)。然后在相应的 cpp 文件中定义/编码所有这些方法(在 cpp 中定义这些方法的作用)。我对这一切都很好。我不明白的是,为什么在头文件中我们需要声明其他名称空间(包含其方法接口的描述)。
  • @Roman 我已经添加了一个示例来说明为什么会发生这种情况。这可能就是您所看到的。
  • 谢谢。现在更清楚了。我们在people.h 中声明了其他名称空间,因为我们想使用这些名称空间中的“成员”(类或方法或变量)。我还不清楚的是,为什么我们不能只包含这些命名空间的标题(然后我们可以使用这些命名空间的任何成员)。
  • @Roman 与我们使用没有命名空间的前向声明的原因相同。包含头文件会引入依赖关系并增加编译时间。如果您只需要某个类的前向声明,那么包括整个头文件是没有意义的。
  • @Roman:编译器不需要知道dogs命名空间的类实际定义在哪里,这就是前向声明的重点。前向声明仅告诉编译器存在某种类型,而不精确其内容。当您实际上需要知道这些类型的内容时,您将包含适当的标题。如果您查看people.cpp,您可能会看到一些#include 指令用于etet::datexsystem::estimation_module,因为实现文件(.cpp)需要这些类型的完整定义。
猜你喜欢
  • 2022-07-06
  • 2015-02-10
  • 2014-11-23
  • 2015-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 2013-10-16
相关资源
最近更新 更多