c++在多个源文件中包含具有相同类实现的不同头文件

时间:2022-11-29 02:06:04

For example

例如

a.h

a.h

class Dummy {
public:
  Dummy() { std::cout << "a.h" << std::endl; }
};

b.h

b.h

class Dummy {
public:
  Dummy() { std::cout << "b.h" << std::endl; }
};

c.cc

c.cc

#include "a.h"

void test() {
  Dummy a;
}

d.cc

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?

我的问题是为什么没有多重定义错误,为什么输出取决于编译的顺序?

2 个解决方案

#1


8  

Your program has undefined behavior. To summarize the C++ standard's take, here's [basic.def.odr/6] with my emphasis:

你的程序有未定义的行为。下面是[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

一个类类型可以有多个定义,[……][参考译文]在一个程序中,如果每个定义出现在一个不同的翻译单元中,并提供满足以下要求的定义。给定一个在多个翻译单元中定义的名为D的实体

  • each definition of D shall consist of the same sequence of tokens; and

    D的每个定义都由相同的令牌序列组成;和

  • [...]

    […]

[...] 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.

[…[参考译文]如果D的定义满足了所有这些要求,那么行为就好像有一个D的定义,如果D的定义不满足这些要求,那么行为就没有定义。

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".

现在,从实际的角度来看,你所看到的只是按照上述合同运作的GCC。它假定您不会违反它(即使您这样做了),并且忽略任何后续对哑人和/或其成员的重新定义。第一个“胜出”。

#2


3  

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.

编译器不会检测到多重定义错误,因为c。cc和d。cc是独立的翻译单位。它们是分开处理的;每一个都有一个哑构造函数的定义:::哑构造函数。

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.

当程序违反这条规则时,它的行为是未定义的。这就是为什么你的程序会因为在翻译过程中改变翻译单元的顺序而表现出不同的行为。

#1


8  

Your program has undefined behavior. To summarize the C++ standard's take, here's [basic.def.odr/6] with my emphasis:

你的程序有未定义的行为。下面是[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

一个类类型可以有多个定义,[……][参考译文]在一个程序中,如果每个定义出现在一个不同的翻译单元中,并提供满足以下要求的定义。给定一个在多个翻译单元中定义的名为D的实体

  • each definition of D shall consist of the same sequence of tokens; and

    D的每个定义都由相同的令牌序列组成;和

  • [...]

    […]

[...] 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.

[…[参考译文]如果D的定义满足了所有这些要求,那么行为就好像有一个D的定义,如果D的定义不满足这些要求,那么行为就没有定义。

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".

现在,从实际的角度来看,你所看到的只是按照上述合同运作的GCC。它假定您不会违反它(即使您这样做了),并且忽略任何后续对哑人和/或其成员的重新定义。第一个“胜出”。

#2


3  

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.

编译器不会检测到多重定义错误,因为c。cc和d。cc是独立的翻译单位。它们是分开处理的;每一个都有一个哑构造函数的定义:::哑构造函数。

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.

当程序违反这条规则时,它的行为是未定义的。这就是为什么你的程序会因为在翻译过程中改变翻译单元的顺序而表现出不同的行为。