Исключение из правила "только одна реализация"?

Пока я читал принятый ответ этот вопрос, у меня был следующий вопрос:

Как правило, методы определяются в файлах заголовков (.hpp или что-то еще) и реализации в исходных файлах (.cpp или что-то еще).

Одной из основных причин, по которым некорректная практика когда-либо включать "исходный файл" (#include <source_file.cpp>), заключается в том, что реализация его методов затем будет дублироваться, что приведет к связыванию ошибок.

Когда вы пишете:

#ifndef BRITNEYSPEARS_HPP
#define BRITNEYSPEARS_HPP

class BritneySpears
{
  public:

    BritneySpears() {}; // Here the constructor has implementation.
};

#endif /* BRITNEYSPEARS_HPP */

Он дает реализацию конструктора (здесь "пустая" реализация, но все же).

Но почему тогда, включая этот заголовочный файл несколько раз (ака. на разные исходные файлы), будет не генерировать ошибку "повторного определения" во время ссылки?

Ответ 1

Встроенные функции являются исключениями из "одного правила определения": вам разрешено иметь идентичные реализации из них в нескольких блоках компиляции. Функции являются встроенными, если они объявлены inline или реализованы внутри определения класса.

Ответ 2

Функции-члены с реализацией внутри определения класса рассматриваются как встроенные функции. Встроенные функции освобождаются от одного правила определения.

В частности, когда компоновщик видит две встроенные функции с одной и той же сигнатурой, они рассматривают их так, как будто это одна и та же функция, и просто выбирает один из них. Это может привести к действительно странно трудно обнаружить проблемы.

Ответ 3

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

Компилятор также попытается привести их в строку, поэтому в приведенном выше примере компилятор полностью попытается полностью исключить вызов конструктора.