c++ включает различные заголовочные файлы с одинаковой реализацией класса в нескольких исходных файлах


Например

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 и почему результат зависит от порядка компиляции?

2 7

2 ответа:

Ваша программа имеет неопределенное поведение. Чтобы суммировать взятие стандарта C++, вот [basic.защита.odr / 6] с моим акцентом:

Может быть более одного определения типа класса, [...] в программа при условии, что каждое определение появляется в другом единицы перевода, а также при условии, что определения удовлетворяют следующим требованиям: требования. Дана такая сущность с именем D, определенная более чем в одном единица перевода, тогда

  • Каждое определение D состоит из той же последовательности знаков ; и

  • [...]

[...] Если определения D удовлетворяют всем этим требованиям, то поведение таково, как если бы существовало единственное определение D. , Если определения D не удовлетворяют этим требованиям, то поведение не определено.

Таким образом, вы наблюдаете два различных поведения. Вполне приемлемо, учитывая, что язык не накладывает никаких ограничений на то, как вы себя ведете. надо бы еще посмотреть. Вы нарушили договор, поэтому никаких гарантий нет. Теперь, с практической точки зрения, то, что вы видите, происходит-это просто GCC, работающий по вышеуказанному контракту. Он предполагает, что вы не нарушите его (даже если вы это сделаете), и просто игнорирует любые последующие переопределения Dummy и/или его членов. Первый из них "побеждает".

Компилятор не обнаруживает ошибки множественного определения, поскольку c.cc и d.cc являются отдельными единицами перевода. Они обрабатываются отдельно друг от друга; каждый имеет ровно одно определение конструктора Dummy::Dummy.

Компоновщик

Не обнаруживает ошибки множественного определения, поскольку определение конструктора Dummy::Dummy из заголовка рассматривается как встроенное определение. Язык позволяет встроенное определение в каждой единице перевода, если все они идентичны. Обычно причина, по которой эти определения идентичны, заключается в том, что все они исходят из одного и того же файла заголовка, но стандарт требует, чтобы определения были идентичными, даже если они исходят из разных файлов.

Когда ваша программа нарушает это правило, ее поведение не определено. Вот почему ваша программа ведет себя по-разному в зависимости от, казалось бы, несвязанного акта изменения порядка единиц перевода во время перевода.