繁体   English   中英

为什么在多个.cpp文件中定义相同的类不会导致链接器多重定义错误?

[英]Why does the same class being defined in multiple .cpp files not cause a linker multiple definition error?

我有一种奇怪的行为,我不明白。 所以我有两个不同的类,在两个不同的cpp文件中定义了相同的名称。 据我所知,这不会在编译翻译单元时造成任何错误,因为他们彼此不了解。 但是链接器将这些文件链接在一起时不应该抛出一些错误吗?

你正在考虑一个定义规则 我从那里引用(粗体是我选择的重点,而不是原始文件的一部分)。

您的理解是正确的 - 在多个编译单元中定义相同的函数是非法的:

每个非内联函数或变量使用的一个且仅有一个定义(见下文)需要出现在整个程序中(包括任何标准和用户定义的库)。 编译器不需要诊断此违规,但是违反它的程序的行为是未定义的。

但是,对于类来说不是这种情况,可以多次定义(每个编译单元最多一次),只要定义全部相同即可。 如果它们是相同的,那么您可以安全地将该类的实例从一个编译单元传递到另一个编译单元,因为所有编译单元都具有兼容的相同大小和内存布局的相同定义。

在任何一个翻译单元中只允许任何变量,函数, 类类型 ,枚举类型,概念(因为C ++ 20)或模板的一个定义(其中一些可能有多个声明,但只允许一个定义)。

...

程序中可以有多个定义,只要每个定义出现在以下各项的不同翻译单元中: 类类型 ,枚举类型,内联函数与外部链接内联变量和外部链接(从C ++开始) 17),类模板,非静态函数模板,类模板的静态数据成员,类模板的成员函数,部分模板特化,概念,(自C ++ 20以来)只要满足以下所有条件:

  • 每个定义由相同的令牌序列组成(通常出现在同一个头文件中)
  • 每个定义中的名称查找找到相同的实体(在重载解析之后),除了具有内部链接或没有链接的常量可以引用不同的对象,只要它们不是ODR使用并且在每个定义中具有相同的值。
  • 重载运算符(包括转换,分配和释放函数)引用每个定义中的相同函数(除非引用定义中定义的函数),语言链接是相同的(例如,包含文件不在extern“C”块内)
  • 上述三条规则适用于每个定义中使用的每个默认参数
  • 如果定义是针对具有隐式声明的构造函数的类,则每个使用odr的翻译单元必须为基础和成员调用相同的构造函数
  • 如果定义是针对模板的,那么所有这些要求都适用于定义时的两个名称和实例化时的依赖名称

如果满足所有这些要求,则程序的行为就好像整个程序中只有一个定义。 否则,行为未定义。

这些要点是一种奇特而高度精确的方式,用于指定定义必须相同,字母和有效结果。

只要这些定义完全,无掺杂, 相同单定义规则就明确允许这样做。

而且我的意思是完全相同。 即使您为令牌class交换令牌struct如果它无关紧要 ,您的程序也会有未定义的行为。

这是有充分理由的:通常我们在标题中定义类,我们通常将这些标题包含在多个翻译单元中; 如果不允许的话会很尴尬。

出于同样的原因,这同样适用于inline函数定义。

至于为什么你没有得到错误:好吧,就像我说的,未定义的行为。 从技术上讲,工具链可能会对此进行诊断,但由于多个具有相同名称的类定义是一个非常普遍的事情(上图),因此可能会浪费时间来提出一个相当复杂的逻辑。所有事物的联系人都试图诊断“事故”。 最终,正如在这种语言中的许多事情一样,你可以试着把它弄好。

暂无
暂无

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

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