C++:命名空间——如何在头文件和源文件中正确使用?

Posted

技术标签:

【中文标题】C++:命名空间——如何在头文件和源文件中正确使用?【英文标题】:C++: Namespaces -- How to use in header and source files correctly? 【发布时间】:2012-06-04 16:57:48 【问题描述】:

考虑一对两个源文件:一个接口声明文件(*.h*.hpp)及其实现文件(*.cpp)。

*.h 文件如下所示:

namespace MyNamespace 
  class MyClass 
  public:
    int foo();
  ;

我已经看到了在源文件中使用命名空间的两种不同做法:

*.cpp 展示练习#1:

#include "MyClass.h"
using namespace MyNamespace;

int MyClass::foo()  ... 

*.cpp 展示练习#2:

#include "MyClass.h"
namespace MyNamespace 

  int MyClass::foo()  ... 


我的问题:这两种做法之间有什么区别吗?一种被认为比另一种更好吗?

【问题讨论】:

还有选项 3:只有我们全名,例如int MyNamespace::MyClass::foo() .... 可能重复:***.com/questions/7789163/… @Dave 不重复。这些问题相辅相成。建议将 Dave 提供的链接添加为“Read also ...”到这个问题。我的问题会帮助新手选择正确的风格。 可能重复:***.com/questions/8210935/… 【参考方案1】:

从代码可读性的角度来看,出于这个原因,我认为使用#2 方法可能更好:

您可以同时成为using 多个命名空间,并且写在该行下方的任何对象或函数都可以属于这些命名空间中的任何一个(除非命名冲突)。将整个文件包装在 namespace 块中更加明确,并允许您在 .cpp 文件中声明属于该命名空间的新函数和变量

【讨论】:

戴夫在他对您的问题的评论中链接的问题还概述了您正在查看的两种方法之间差异(如果有的话)的一些关键点 各位,我真的不知道该选择谁的答案。他们有交集,又相辅相成。 只是评论承认某些 IDE 像 CLion 只会在您使用选项/实践 #2 时检测实现。 @PedroTanaka 还是这样吗?我没有注意到任何此类问题。 @JMcF 自从我发表评论以来,我还没有检查过。在早期版本的 Clion 中出现了问题。【参考方案2】:

最清楚的是你没有显示的选项:

int MyNamespace::MyClass::foo()

    //  ...

它也很冗长;对大多数人来说太多了。由于using namespace 是名称冲突的原因,至少在我的经验中, 并且应该避免,除非在非常有限的范围和地方,我 通常使用你的#2。

【讨论】:

非常感谢。我们一起为命名空间用户制作了一个很好的常见问题解答页面。 :) 各位,我真的不知道该选择谁的答案。他们有交集,又相辅相成。【参考方案3】:

这两种做法有什么区别

是的。 #1 和 #2 分别是 using-directive 和 namespace definition 的示例。在这种情况下,它们实际上是相同的,但会产生其他后果。例如,如果您在 MyClass::foo 旁边引入一个新标识符,它将具有不同的范围:

#1:

using namespace MyNamespace;
int x;  // defines ::x

#2:

namespace MyNamespace 
  int x;  // defines MyNamespace::x

一个被认为比另一个更好吗?

#1 优点:更简洁;更难不经意间将某些东西引入MyNamespace。缺点:可能会无意中引入现有的标识符。

#2 优点:更清楚的是现有标识符的定义和新标识符的声明都属于MyNamespace。缺点:更容易无意中将标识符引入MyNamespace

对#1 和#2 的批评是,当您可能只关心MyNamespace::MyClass 成员的定义时,它们指的是整个命名空间。这是严厉的,它传达的意图很差。

#1 的可能替代方法是 using-declaration,其中仅包含您感兴趣的标识符:

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo()  ... 

【讨论】:

【参考方案4】:

我还想补充一点,如果您由于某种原因决定在 cpp 文件中实现模板特化并仅依赖using namespace,您将遇到以下问题:

// .h file
namespace someNameSpace

  template<typename T>
    class Demo
    
      void foo();
    ;


// .cpp file
using namespace someNameSpace;

template<typename T>
void Demo<T>::foo()

// this will produce
// error: specialization of 'template<class T> void someNameSpace::Demo<T>::foo()' in different namespace [-fpermissive]
template<>
void Demo<int>::foo()

否则如果你应用#2方法就可以了。

【讨论】:

【参考方案5】:

我想再添加一种方式,使用 using-declaration

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo()  ... 

如果类有很多功能,这种方式可以避免你多次输入命名空间名称

【讨论】:

【参考方案6】:

我认为实践#1 根本不是正确的 C++ 代码。这段代码 sn-p 定义了 ::MyClass::foo 符号,其中真正的全限定名是 ::MyNamespace::MyClass::foo。

要了解命名空间,您可以阅读草案的第 7.3 节,假设标准 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf

这个概念从 1998 年左右开始就已经很老了,所以你可以使用 B.Stroustroup 的任何标准或书籍来了解它。

在 C++ 语言中,命名空间 是一个命名范围。与类定义相反,命名空间可以向其添加新功能。

C++中的构造“using namespace NS;”被称为using-directive,在我的实践中它可以用于几个目标:

    您可以在另一个命名空间中使用此指令来组合(混合)来自不同命名空间的名称。 在编译单元的上下文中,它会将同义词附加到命名空间 NS 中的所有变量。

要定义符号,您可以使用两种机制 - 您可以通过在 C++ 源文件中的全局命名空间中操作,对所有命名空间使用显式限定。

或者您可以打开命名空间并向其添加定义(练习 #2)。

【讨论】:

以上是关于C++:命名空间——如何在头文件和源文件中正确使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用命名空间和类?

C++不使用匿名命名空间实现内部链接

C++ 中未命名命名空间的使用

用于头文件中的匿名命名空间

在头文件中定义命名空间类

devc++格式为啥那么丑