Hen*_*ise 9 c++ one-definition-rule
我遇到一种我不理解的奇怪行为。因此,我在两个不同的cpp文件中定义了两个具有相同名称的不同类。我知道这不会在翻译单元的编译过程中引起任何错误,因为他们彼此之间并不了解。但是,链接器将这些文件链接在一起时,是否不应该抛出一些错误?
您正在考虑一个定义规则。我从那里引用(粗体是我选择的重点,而不是原始文件的一部分)。
您的理解是正确的——在多个编译单元中定义相同的函数是非法的:
odr 使用的每个非内联函数或变量(见下文)的一个且仅一个定义需要出现在整个程序(包括任何标准和用户定义的库)中。编译器不需要诊断这种违反,但违反它的程序的行为是未定义的。
但是,对于类而言,情况并非如此,只要定义完全相同,就可以多次定义类(在每个编译单元中最多定义一次)。如果它们相同,那么您可以安全地将该类的实例从一个编译单元传递到另一个编译单元,因为所有编译单元都具有兼容的、相同的定义以及兼容的大小和内存布局。
在任何一个翻译单元中只允许对任何变量、函数、类类型、枚举类型、概念(C++20 起)或模板有一个定义(其中一些可能有多个声明,但只允许一个定义)。
...
一个程序中可以有多个定义,只要每个定义出现在不同的翻译单元中,分别是:类类型、枚举类型、具有外部链接的内联函数具有外部链接的内联变量(自 C++ 17)、类模板、非静态函数模板、类模板的静态数据成员、类模板的成员函数、部分模板特化、概念,(C++20 起),只要满足以下所有条件:
- 每个定义由相同的标记序列组成(通常出现在同一个头文件中)
- 每个定义中的名称查找会找到相同的实体(在重载解析之后),除了具有内部链接或没有链接的常量可以引用不同的对象,只要它们不是 ODR 使用的并且在每个定义中具有相同的值。
- 重载运算符,包括转换、分配和解除分配函数从每个定义中引用相同的函数(除非引用定义中定义的函数) 语言链接是相同的(例如包含文件不在 extern "C" 块中)
- 上述三个规则适用于每个定义中使用的每个默认参数
- 如果定义是针对具有隐式声明构造函数的类,则每个使用 odr 的翻译单元都必须为基类和成员调用相同的构造函数
- 如果定义是针对模板的,那么所有这些要求都适用于定义点的名称和实例化点的从属名称
如果满足所有这些要求,则程序的行为就好像整个程序中只有一个定义。否则,行为是未定义的。
要点是一种花哨且高度精确的方式,用于指定定义必须在字母和有效结果上相同。