在不同源文件中声明的同名类没有编译器/链接器错误

Posted

技术标签:

【中文标题】在不同源文件中声明的同名类没有编译器/链接器错误【英文标题】:No compiler/linker error for same name classes declared in different source files 【发布时间】:2013-07-14 13:07:48 【问题描述】:

我有如下 2 个文件,它们声明了同名 class C:

// C1.cpp
class C  
public: void foo (int, float);
;

int main () 
  C c;
  c.foo(1, 2.3);


void C::foo (int, float) 

// C2.cpp
class C  
public:
  int i;  // <--- extra variable
  void foo (int, float);  // <--- non static
;

void foo () 
  C c;
  c.foo(0, 0.0);
  c.i = 0;

它与g++ C1.cpp C2.cpp 编译得很好!

    为什么只有名称相同时没有编译器/链接器错误 但尸体不是? 为什么C::foo(..) 的单一定义同时适用于 static 和非静态版本? 或者如果这只是编译器的另一个未定义行为案例, 我们可以预防吗?

【问题讨论】:

我认为这是“UB,不需要诊断”。 @downvoter,这个问题还不足以被否决。 您需要标准报价吗?它基本上说“一个类可以有多个定义,但它们都需要由相同的标记序列组成”和“定义中的所有名称都需要引用相同的实体”。正如 Kerred 所说,1)和 2)的答案是 UB,不需要诊断。 3) 的答案是,我猜,就是不要这样做。 @jrok,我不知道应该是什么答案。如果您觉得有什么可以帮助的,请发布它。这将对我和未来的访客有所帮助。我在 SO 中找不到类似的问题。对 (3) 的回答不能是“不要这样做”,当您有多个人参与庞大的代码库时,在最坏的情况下它必须是“不可能”。 【参考方案1】:

您的程序违反了One definition rule 并且具有未定义的行为。来自n3337 3.2/5,强调我的:

类类型可以有多个定义(第 9 条)、枚举类型 (7.2)、内联函数 外部链接(7.1.2),类模板(第 14 条),非静态函数模板(14.5.6),静态数据成员 类模板 (14.5.1.3) 的成员函数、类模板的成员函数 (14.5.1.1) 或模板特化 某些模板参数在程序中未指定(14.7、14.5.5)只要每个定义 出现在不同的翻译单元中,并且定义满足以下要求。给定 这样一个名为 D 的实体定义在多个翻译单元中,那么

D 的每个定义都应由相同的标记序列组成;

——在D的每个定义中,对应的名字,根据 至 3.4,应指在 D 的定义中定义的实体,或 在重载决议(13.3)和 在匹配部分模板特化(14.8.3)之后,除了 一个名称可以引用一个具有内部链接或没有链接的 const 对象,如果 该对象在 D 的所有定义中都具有相同的字面量类型,并且 对象用常量表达式(5.19)初始化,值 对象的(但不是地址)被使用,并且对象具有 D 的所有定义中的值相同;和

[...省略了与示例不直接相关的内容...]

如果 D 的定义满足所有这些要求, 那么程序的行为就好像有一个 D 的定义。如果 D 的定义不满足 这些要求,则行为未定义

您不会收到编译器错误,因为它一次只能“看到”一个翻译单元。链接器及其错误消息超出了 C++ 标准的范围,所以我相信无法de iure 回答为什么它不能诊断。我猜它只需要遇到并丢弃其余符号的第一个 C 符号。

【讨论】:

以上是关于在不同源文件中声明的同名类没有编译器/链接器错误的主要内容,如果未能解决你的问题,请参考以下文章

在 C 中声明两个同名的全局变量

C中定义不同的同名结构

NASM 汇编器,如何定义标签两次?

将结构前向声明为类时出现 Visual C++ 2015 链接器错误

使用编译器/链接器进行 C++ 代码清理

“编译为”设置为“默认”时的外部符号链接错误[重复]