c ++在多个源文件中包含具有相同实现class的不同头文件
c++ include different header files with same implementation of class in multiple source files
例如
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
错误,为什么输出取决于编译的顺序?
您的程序有未定义的行为。为了总结 C++ 标准的做法,这里是 [basic.def.odr/6] 我的重点:
There can be more than one definition of a class type, [...] in a
program provided that each definition appears in a different
translation unit, and provided the definitions satisfy the following
requirements. Given such an entity named D defined in more than one
translation unit, then
each definition of D shall consist of the same sequence of tokens; and
[...]
[...] If the definitions of D satisfy all these requirements, then the
behavior is as if there were a single definition of D. If the
definitions of D do not satisfy these requirements, then the behavior
is undefined.
所以你观察到两种不同的行为。完全可以接受,因为语言对您应该看到的行为没有任何限制。你违反了合同,所以没有任何保证。
现在,从实际的角度来看,您所看到的只是 GCC 在上述合同下运行。它假定您不会违反它(即使您这样做),并且只是忽略 Dummy
and/or 其成员的任何后续重新定义。第一个"wins out".
编译器未检测到多重定义错误,因为 c.cc
和 d.cc
是不同的 翻译单元 。它们彼此分开处理;每个都有 Dummy::Dummy
构造函数的一个定义。
链接器未检测到多重定义错误,因为来自 header 的 Dummy::Dummy
构造函数的定义被视为内联定义。该语言允许在每个翻译单元中进行内联定义,只要它们都是相同的。通常,这些定义相同的原因是它们都来自同一个 header 文件,但标准要求定义相同,即使它们来自不同的文件。
当您的程序违反此规则时,其行为是未定义的。这就是为什么您的程序会根据看似无关的在翻译过程中更改翻译单元顺序的行为而表现不同。
例如
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
错误,为什么输出取决于编译的顺序?
您的程序有未定义的行为。为了总结 C++ 标准的做法,这里是 [basic.def.odr/6] 我的重点:
There can be more than one definition of a class type, [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
each definition of D shall consist of the same sequence of tokens; and
[...]
[...] If the definitions of D satisfy all these requirements, then the behavior is as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.
所以你观察到两种不同的行为。完全可以接受,因为语言对您应该看到的行为没有任何限制。你违反了合同,所以没有任何保证。
现在,从实际的角度来看,您所看到的只是 GCC 在上述合同下运行。它假定您不会违反它(即使您这样做),并且只是忽略 Dummy
and/or 其成员的任何后续重新定义。第一个"wins out".
编译器未检测到多重定义错误,因为 c.cc
和 d.cc
是不同的 翻译单元 。它们彼此分开处理;每个都有 Dummy::Dummy
构造函数的一个定义。
链接器未检测到多重定义错误,因为来自 header 的 Dummy::Dummy
构造函数的定义被视为内联定义。该语言允许在每个翻译单元中进行内联定义,只要它们都是相同的。通常,这些定义相同的原因是它们都来自同一个 header 文件,但标准要求定义相同,即使它们来自不同的文件。
当您的程序违反此规则时,其行为是未定义的。这就是为什么您的程序会根据看似无关的在翻译过程中更改翻译单元顺序的行为而表现不同。