例如
A.H
class Dummy {
public:
Dummy() { std::cout << "a.h" << std::endl; }
};
b.h
class Dummy {
public:
Dummy() { std::cout << "b.h" << std::endl; }
};
c.cc
#include "a.h"
void test() {
Dummy a;
}
d.cc
#include "b.h"
int main() {
Dummy a;
return 0;
}
然后使用命令
编译源文件g++ d.cc c.cc
输出
b.h
但是有了命令
g++ c.cc d.cc
输出
a.h
我的问题是为什么没有multiple definition
错误以及为什么输出取决于编译的顺序?
答案 0 :(得分:8)
您的程序有未定义的行为。总结一下C ++标准,我的重点是[basic.def.odr/6]:
a类中可以有多个定义,[...] 程序规定每个定义出现在不同的地方 翻译单元,并提供满足以下要求的定义 要求。鉴于这样一个名为D的实体在多个中定义 翻译单位,然后
D的每个定义应由相同的令牌序列组成;以及
[...]
[...]如果D的定义满足所有这些要求,那么 行为就好像有一个单一的D定义。如果 D的定义不满足这些要求,那么行为 未定义。
所以你观察到两种不同的行为。完全可以接受,因为语言对你应该看到的行为没有任何限制。你违反了合同,所以没有保证。
现在,从实际的角度来看,你看到的只是GCC根据上述合同运作。它假定您不会违反它(即使您这样做),并且只是忽略Dummy
和/或其成员的任何后续重新定义。第一个&#34;胜出&#34;。
答案 1 :(得分:3)
编译器未检测到多重定义错误,因为c.cc
和d.cc
是单独的翻译单元。它们彼此分开处理;每个都只有Dummy::Dummy
构造函数的一个定义。
链接器未检测到多重定义错误,因为标头中Dummy::Dummy
构造函数的定义被视为内联定义。该语言允许每个翻译单元中的内联定义,只要它们全部相同即可。通常,这些定义相同的原因是它们都来自相同的头文件,但标准要求定义相同,即使它们来自不同的文件。
当您的程序违反此规则时,其行为未定义。这就是为什么你的程序表现不同,这取决于在翻译过程中改变翻译单元顺序的看似无关的行为。