Незыблемых правил два.
1. В CPP первым — свой хедер. Это даёт уверенность, что в хедере нет недостающих включений.
2. Избегать циклической зависимости по интерфейсам. Делить программу на слои и не включать ничего из верхних слоёв.
Если уж второе не получилось — есть три решения, каждое из которых решает свою задачу.
1. Forward declaration, полумера против сильной связанности классов.
// Хедер 1
class Master;
class Slave {
Master* master;
}
// Хедер 2
class Master {
Slave slave;
}
2. Разорвать порочный круг интерфейсом.
// Хедер 1
class Master { // interface
public:
virtual void enumSlaves(const EnumSlavesCallback& v) = 0;
virtual ~Master() = default;
}
class Slave {
Master* master;
}
// Хедер 2
class MyMaster : public Master {
public:
Slave slave;
void enumSlaves(const EnumSlavesCallback& v) override {}
}
3. Вынести общие типы/функции в отдельный хедер под названием someDefines.h или someUtils.h.