@vipermagi
Вечный ученик.

Когда имеет значение порядок подключения заголовочных файлов?

Вот попался такой случай. В заголовочнике одного класса определён shared::ptr на другой класс. В реализации был подключен самым первым собственный заголовочник, следом за ним подключен заголовочник класса из shared::ptr. При этом выдавало ошибку компиляции invalid use of incomplete type 'class myclass'. Как только я поменял местами эти два подключения в реализации, то всё стало компилить без ошибок.

Вопрос 1: почему в данном случае выдавало ошибку?
Вопрос 2: когда в общем случае имеет значение порядок подключения заголовочных файлов?

*UPDATE*
Щас выяснил, что такое поведение проявлялось, когда в заголовочном файле и файле реализации собственно класс и реализации методов были завёрнуты в namespace, а предварительные объявления и простые #include были снаружи. Вот я перенёс предварительные объявления внутрь namespace и смена порядка включения заголовочников этих класов в реализации перестала волновать компилятор.

Я чё-то совсем запутался, в чём дело.
  • Вопрос задан
  • 1006 просмотров
Решения вопроса 1
@Mercury13
Программист на «си с крестами» и не только
Заголовочные файлы надо писать так, чтобы порядок их подключения был неважен.

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

Совать #include в пространство имён без хорошего обоснования не стоит.

По вашему обтекаемому описанию не видно, как устроены ваши заголовки, именованное пространство имён или нет, закрыты ли все скобки в хедерах, и т.д. Но причина ошибки очевидна: из-за пространств имён компилятор не отождествил классы в первом и втором заголовке; предварительное объявление «class A;» осталось неразрешённым. Поэкспериментировав, я выяснил вот что.
// Не компилируется!
class A;

namespace XXX {
    std::shared_ptr<A> a;
    class A { public: int x; };
    void xxx();
}

void XXX::xxx() {
    a->x;
}


// Компилируется!
class A;

namespace XXX {
    class A { public: int x; };
    std::shared_ptr<A> a;
    void xxx();
}

void XXX::xxx() {
    a->x;
}

// Тоже компилируется!
namespace XXX {
    class A;
}

namespace XXX {
    std::shared_ptr<A> a;
    class A { public: int x; };
    void xxx();
}

void XXX::xxx() {
    a->x;
}

В первом случае shared_ptr<::A>, который, естественно, не определён (есть XXX::A).
Во втором — определение наперёд ::A вообще ни на что не сдалось; используется shared_ptr<XXX::A>.
В третьем примере только один тип, XXX::A.

Если первым идёт не использование, а make_shared — выходит другая ошибка, не удаётся получить sizeof недоопределённого типа A.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы