У вас есть один файл, который включает в себя другой, и наоборот. Это создает цикл включения.
Поймите, что макрос #include
не делает ничего, кроме как заменить себя (то есть, это строка) другим файлом. Это делает очевидным, почему у вас не может быть файла A, включающего файл B.
Очевидное решение - поместить предварительное объявление Boo в Foo:
#ifndef Foo_hpp
#define Foo_hpp
#include <stdio.h>
class Boo;
class Foo
{
public:
...
Странно, вы уже сделали это до того, как разделили их.
Теперь немного больше теории для вас: класс технически является хранилищем данных. Он должен знать его размер, чтобы зарезервировать память. Следовательно, ему нужно знать все размеры его членов, которые он может знать только тогда, когда они объявлены. Поэтому класс должен включать объявления заголовков каждого класса, который он имеет в качестве члена. Тем не менее, указатель на объект отличается (то же самое касается ссылок). Указатель всегда принимает один и тот же размер, то есть 32 или 64 бита, в зависимости от вашей платформы (вероятно, 64-битной, поскольку в настоящее время у нас есть 64-битные платформы). Следовательно, классу не нужно знать класс, на который он указывает, память, которую он резервирует для своего элемента указателя, всегда имеет одинаковый размер. Вот почему предварительное объявление, которое ничего не говорит о размере классов, здесь хорошо.