Включаемый файл включает самого себя
Есть три файла: DllMain.h, Player.h и Chest.h. У каждого из этих файлов есть так же .cpp где находится сам код. В заголовочных файлах только объявления и разные #include. Каждый из этих трёх файлов должен иметь доступ к вызовам OpenGL функций (GL.h) DllMain должен иметь возможность вызывать функции draw() из Player.h и Chest.h. А Player.h и Chest.h должны иметь возможность вызывать OpenGL функции. Если подключать GL.h ко всем трем файлам, то будет много разных ошибок. Если в Player.h и Chest.h написать #include "DllMain.h" в котором прописано #include "GL.h", то нужно ещё подключить Player.h и Chest.h в DllMain.h иначе я из DllMain.h не буду иметь возможность вызывать draw() в Player.h и Chest.h. И тут появляется ошибка когда файл включает самого себя. Как решить эту проблему более правильно?
Ответы (2 шт):
Судя по описанию в cpp-файл два раза попадает один и тот же заголовочный файл, например:
DllMain.cpp <- Chest.h <- Player.h
<- Player.h
То еcть в логике DllMain необходимо работать с двумя сущностями: Player и Chest. В свою очередь сущности Chest нужен Player.
DllMain.cpp:
#include "Chest.h"
#include "Player.h"
...
Chest.h:
#include "Player.h"
Chest.cpp:
#include "Chest.h"
Это вполне адекватная ситуация, нюанс в том что компилятор при обработке #include вставляет все содержимое файла, в итоге получаем ошибки множественного определения. Чтобы это исправить нужно в начале каждого заголовочного файла писать #pragma once, либо:
Chest.h:
#if defined CHEST_H
#define CHEST_H
...
#endif
У С++ одна из основных проблем это хедеры.
Хедеры это такой хак, чтобы можно было писать большие программы, несмотря на то что рефлексии и рантайма нет. Всё что делает препроцессор на #include , это вставляет содержимое файла вместо этой строки, и НИЧЕГО кроме этого.
Пускай есть 4 файла
a.h
int a(int l);
a.cpp
#include "a.h"
#include "b.h"
int a(int l){
if(l<=0) return 1;
return b(l-1)+2;
}
b.h
int b(int l);
b.cpp
#include "a.h"
#include "b.h"
int b(int l){
if(l<=0) return 1;
return a(l-1)*3;
}
Фактически компилятору серавно что в хедерах, пока он не встретит инклуд, он их будет игнорировать. И для него эти файлы будут выглядеть так:
a_complie_unit
int a(int l);
int b(int l);
int a(int l){
if(l<=0) return 1;
return b(l-1)+2;
}
b_complie_unit
int a(int l);
int b(int l);
int b(int l){
if(l<=0) return 1;
return a(l-1)*3;
}
Так как объявление классов можно делать только 1 раз, и чтобы не вставлять 100 одинаковых копий текста, во всех компилчторах есть второй хак:
#pragma once
всё что он делает, это запрещает второй раз включать этот файл.
Теперь что касается 3 файлов друг на друга: Включать хедер в хедере нужно если:
- нужны объявления клссов/структур
- или нужны функции из хедеров для темплейтовых или инлайновых функций(для обычных функций вллючать хедер надо в .cpp а не в .h)
Также стоит учесть что для передачи аргументов и возврата по ссылке, а также возвращаемого значения функций достаточно форвард декларации.
И если есть 3 хедера включающих друг друга значит это реально где-то проблема, не должно быть циклического инклуда, прагма онц тут только скроет проблему, но не решит её, она вернётся потом.
Если подключать GL.h ко всем трем файлам, то будет много разных ошибок.
Счегобы? Я всегда так делал. https://gitlab.com/nikitasamoukov/irambis/-/blob/master/irambis/src/pch.h Подключил GLAD ко всем файлам .cpp через предкомпилированный заголовок и всё.
#include <glad/glad.h>