能不能在不同的翻译单元有两个同名同成员函数的类?

Can you have two classes with the same name and the same member function in different translation units?

假设我有两个翻译单元:

//A.cpp
class X
{
};

//B.cpp
class X
{
   int i;
};

上面的程序是否合式?

如果没有,没有进一步的问题。如果答案是肯定的,程序是良构的(忽略main的缺失),那么第二个问题。如果其中有同名函数怎么办?

//A.cpp
class X
{
    void f(){}
};

//B.cpp
class X
{
    int i;
    void f(){}
};

这对链接器来说是个问题吗,因为它会在两个目标文件中看到 &X::f ?在这种情况下是否必须使用匿名名称空间?

Is the above program well-formed?

没有。它违反了 One-Definition Rule:

[basic.def.odr]

There can be more than one definition of a

  • class type ([class]),
  • ...

in a program provided that each definition appears in a different translation unit and the definitions satisfy the following requirements. Given such an entity D defined in more than one translation unit, for all definitions of D, or, if D is an unnamed enumeration, for all definitions of D that are reachable at any given program point, the following requirements shall be satisfied.

  • ...
  • Each such definition shall consist of the same sequence of tokens, where the definition of a closure type is ...
  • ...

Are anonymous namespaces a must in such a situation?

如果您需要不同的 class 定义,它们必须是不同的类型。唯一命名的命名空间是一种选择,匿名命名空间是获得唯一(对翻译单元)命名空间的保证方式。

简短版

嗯,不...C++ 假设名称空间中的每个名称都是唯一的。如果你打破这个假设,你有 0 个保证它会工作。

例如,如果您在两个翻译单元(*.o 个文件)中有同名的方法。链接器不知道给定的调用使用哪一个,所以它只会 return 一个错误。

长版

...但实际上是的!

实际上在很多情况下,您可以用同名的 classes/methods 逃脱。

实际上不要在您的程序中使用任何这些技巧!如果编译器认为它会优化生成的程序,那么他们可以自由地做几乎任何事情,因此下面的任何假设都可能被打破。

类 是最简单的。让我们以一些只有 non-static 成员且没有函数的 class 为例。这样的事情甚至不会在编译后的程序中留下任何痕迹。 Classes/structs只是程序员组织数据的工具,所以不需要处理内存池和偏移量。 所以基本上如果你有两个 classes 在不同的编译单元中具有相同的名称,它应该可以工作。编译器处理完它们后,它们将仅包含几条指令,说明将指针在内存中移动多少以访问特定字段。 这里几乎没有任何东西会混淆链接器。

函数和变量(包括静态 class 变量)更棘手,因为编译器经常在 *.o 文件中为它们创建符号。如果你幸运的话,如果没有使用这样的 function/variable ,链接器可能会忽略它们,但我什至不会指望它。 但是,有一些方法可以省略为它们创建符号。静态全局元素或匿名名称空间中的元素在其翻译单元之外不可见,因此链接器不应抱怨它们。此外,内联函数不作为单独的实体存在,因此它们也没有符号,这在这里尤其重要,因为在 classes 内定义的函数默认是内联的。 如果没有符号,链接器不会发现冲突,一切都应该编译。

模板也使用了一些肮脏的技巧,因为它们是在使用它们的每个编译单元中按需编译的,但它们最终在最终程序中作为一个副本结束。我认为这与多个 不同 同名事物的情况不同,所以让我们放弃这个话题。

总而言之,如果您的 classes 没有静态成员并且它们不在其主体之外定义函数,则可能有两个同名的 classes只要您不将它们包含在同一个文件中。 但是,这是非常脆弱的。即使它现在可以工作,新版本的编译器也可能有一些 fix/optimization/change 会破坏这样的程序。 更不用说包含在更大的项目中往往交织在一起的事实,所以很有可能在某个时候你需要将两个文件包含在同一个地方。