繁体   English   中英

匿名命名空间类定义

[英]Anonymous Namespace Class Definition

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

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

    //etc...    

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

SomeHelperFunction[AZ]是仅在该翻译单元中需要的函数,所以我理解为什么它们位于匿名namespace中。 同样, SomeClass也只在该翻译单元中是必需的,但我的印象是,如果您没有全局类声明(例如,在通常包含的头文件中)。

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

那么,鉴于此信息,有人可以阐明为什么原始程序员可能会这样做吗? 也许只是为了将来的预防措施?

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

谢谢!

匿名命名空间在全局级别应用时类似于 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;
}

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

通过这种方式,您不能单独调用A()B()C()函数,但您可以调用CallABC() ,这将一个接一个地调用所有这些函数。

您可以在 main.cpp 中转发声明CallABC()并调用它。 但是您不能在 main.cpp 中转发声明 test.cpp 的 A()、B() 或 C(),因为您将遇到链接错误。

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

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

在 C++ ISO 标准(第 2.3 节)中,您会发现一条名为The One Definition Rule 的规则

由于 C++ 中编译和链接之间的复杂关系,这不是一个非常简单的规则。 大部分细节都在这里

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

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

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

好吧,事实并非如此。 请记住,那些“通用”全局类定义在头文件中。 那些字面意思包括在内,将通用的全局类定义复制到所有翻译单元。 如果您使用另一种方式在多个翻译单元中包含完全相同的类定义(例如宏扩展),那也很好。 但是如果你对同一个类名有不同的定义,你就有未定义行为的风险。 如果幸运的话,链接失败。

直接回答你的问题,我认为这是为了避免 SomeClass 的静态成员的链接器“多重定义”错误。 也就是说,假设 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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM