Обычно это достигается тем, что каждый заголовочный файл предварительно объявляет классы, которые ему нужны до его #include
.Кроме того, в заголовочных файлах не должно быть кода.Таким образом, вы получите:
class Effect;
class Player;
class GameStack;
#include <vector>
// more includes
class EffectContainer { ... }
и эквивалент в каждом месте.Затем в ваших .cpp
файлах вы на самом деле #include
заголовки для других классов.Это будет работать, если ваши объекты не имеют круговой зависимости от расположения в памяти других классов.Это означает, что методы и члены могут ссылаться на другие классы только по ссылке или по указателю (но не по значению).Это может немного усложниться, если у вас есть такие вещи, как
class EffectContainer {
std::Vector<Effect> effects;
}
class Effect {
boost::shared_ptr<EffectContainer> parent;
}
, поскольку расширение шаблона иногда требует полных типов, а не просто предварительно объявленных типов.Один из способов избежать этой проблемы во многих библиотеках - указатель на частный шаблон impl (часто называемый шаблоном PIMPL), где каждый класс определяется следующим образом:
class FooImpl;
class Foo {
FooImpl* impl;
}
, тогда FooImpl
полностью определяется вфайл .cpp
и ваши проблемы округлости могут быть решены.Этот дизайн также полезен, поскольку поддерживает двоичную совместимость между версиями вашей библиотеки.Это немного многословно, но никто не сказал, что C++
был лаконичным языком.