匿名命名空间类定义

时间:2009-07-18 16:08:03

标签: c++ class namespaces anonymous

我正在查看一些(C ++)代码并找到类似这样的内容:

//Foo.cpp
namespace
{
    void SomeHelperFunctionA() {}
    void SomeHelperFunctionB() {}
    void SomeHelperFunctionC() {}

    //etc...    

    class SomeClass //<---
    {
        //Impl
    };
}

SomeHelperFunction[A-Z]是仅在该翻译单元中需要的功能,因此我理解为什么他们使用匿名namespace。类似地,SomeClass也只在该翻译单元中需要,但我的印象是,如果您没有全局类,则可以在不同的翻译单元中使用具有相同名称的类,而不会出现任何类型的命名冲突声明(例如,在通常包含的头文件中)。

我还应该提一下,这个特定的翻译单元包含任何可能声明具有相同名称(SomeClass)的类的标题。

所以,鉴于这些信息,有人可以说明为什么原来的程序员可能会这样做吗?也许只是作为未来的预防措施?

老实说,我以前从未见过匿名命名空间中使用的类。

谢谢!

5 个答案:

答案 0 :(得分:6)

匿名命名空间在全局级别应用时类似于static关键字。

匿名命名空间使得您无法从另一个文件中调用命名空间内的任何内容。

匿名命名空间允许您仅限制当前文件的范围。

程序员可以这样做以避免命名冲突。没有全球名称会以这种方式发生冲突在链接时

示例:

文件:test.cpp

namespace 
{
  void A()
  {
  }
  void B()
  {
  }
  void C()
  {
  }
}

void CallABC()
{ 
  A();
  B();
  C();
}

文件:main.cpp

void CallABC();//You can use ABC from this file but not A, B and C

void A()
{
//Do something different
}

int main(int argc, char** argv)
{
  CallABC();
  A();//<--- calls the local file's A() not the other file. 
  return 0;
}

以上将编译正常。但是,如果您尝试在主体中编写CallABC()函数,则会出现链接错误。

通过这种方式,您无法单独调用A()B()C()个函数,但您可以调用CallABC()来逐个调用所有这些函数。

您可以在main.cpp中转发声明CallABC()并进行调用。但是你不能在main.cpp中转发声明test.cpp的A(),B()和C(),因为你会有一个链接错误。

至于为什么命名空间内有一个类。这是为了确保没有外部文件使用此类。 .cpp中的某些东西可能使用该类。

答案 1 :(得分:1)

如果有人链接此代码并且包含相同命名类的定义,并且此文件在其他实现之前链接,则会发生名称冲突。

答案 2 :(得分:1)

在C ++ ISO标准(第2.3节)中,您将找到一个名为一个定义规则的规则。

由于编译和链接之间C ++之间的复杂关系,这不是一个非常简单的规则。 Most of the details are here

但它适用于作为类成员的函数,因为它们(在链接级别)只是使用长名称函数。

它以稍微不同的方式应用于模板,因为链接器将很乐意丢弃出现在单独的翻译单元(源文件)中的模板类或函数的额外定义。这意味着如果您提供同一模板的两个不同定义,则您的程序具有未定义的行为(最佳情况:其中一个定义将随机默默选择)。

答案 3 :(得分:1)

  

我的印象是,如果您没有全局类声明,您可以在不同的翻译单元中使用具有相同名称的类,而不会出现任何类型的命名冲突

嗯,事实并非如此。请记住,那些“常见”全局类定义位于头文件中。这些都包括在内,将常见的全局类定义复制到所有翻译单元。如果你使用另一种方法在多个翻译单元中包含完全相同的类定义(例如宏扩展),那也没关系。但是,如果对同一个类名有不同的定义,则存在未定义的行为风险。如果你幸运的话会链接失败。

答案 4 :(得分:0)

为了直接回答您的问题,我认为这是为了避免SomeClass的 static 成员出现链接器“多个定义”错误。也就是说,假设SomeClass是在没有匿名命名空间的cpp文件中定义的,并且其中包含一些静态字段和/或静态方法,并且这些静态成员在此cpp文件中的类定义旁边定义。然后这些静态成员获得外部链接(在相应的.o文件的符号表中以GLOBAL形式存在)。

现在您有另一个cpp文件,并且要创建另一个SomeClass(与第一个cpp文件中的那个无关,并且您甚至可能不知道第一个cpp文件中第一个SomeClass的存在)自己的目的,并且没有匿名名称空间。然后,您定义一个与第一个SomeClass的静态成员同名的静态成员。这就是您:您最终会发生链接冲突。

因此,第一个cpp文件的作者应该将第一个SameClass隐藏在一个通用的名称空间中,因为该类显然被认为是实现细节,而不是其他人重用的类。因此,其静态成员不应具有外部链接。

所以总的来说,我想说的是类的非constexpr /非内联静态成员就像全局变量或非内联函数。因此,可以使用匿名名称空间在内部建立它们的链接,就像可以使用static关键字或再次使用匿名名称空间对全局变量和函数进行链接一样。

// .cpp file
namespace 
{
    struct A
    {
        static int i;
    };
}

int A::i;