Reputation: 498
For example
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;
}
Then compile source files with command
g++ d.cc c.cc
output is
b.h
but with command
g++ c.cc d.cc
output is
a.h
My question is why there is no multiple definition
error and why the output depends on compilation's order?
Upvotes: 7
Views: 2373
Reputation: 170064
Your program has undefined behavior. To summarize the C++ standard's take, here's [basic.def.odr/6] with my emphasis:
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.
So you observe two different behaviors. Perfectly acceptable, given the language places no restrictions on what behavior you should even see. You violated the contract, so there are no guarantees.
Now, from a practical standpoint, what you see happen is just GCC operating under the above contract. It assumes you wouldn't violate it (even if you do), and just ignores any subsequent re-definitions of Dummy
and/or its members. The first one "wins out".
Upvotes: 8
Reputation: 726539
The compiler does not detect a multiple definition error because c.cc
and d.cc
are separate translation units. They are processed separately from each other; each has exactly one definition of Dummy::Dummy
constructor.
Linker does not detect a multiple definition error because the definition of Dummy::Dummy
constructor from the header is treated as an inline definition. The language allows an inline definition in each translation unit, as long as all of them are identical. Typically, the reason that these definitions are identical is that they all come from the same header file, but the standard requires the definitions to be identical even if they come from different files.
When your program violates this rule, its behavior is undefined. That is why your program behaves differently depending on a seemingly unrelated act of changing the order of translation units during translation.
Upvotes: 3