Форвардная декларация с вектором типа класса - недопустимый указатель на неполный тип класса

У меня есть два класса: foo и bar. foo включает в себя строку bar и содержит std::vector указателей для отображения объектов. в какой-то момент во время выполнения бар должен получить доступ к этому вектору указателей к другим объектам бара. Поэтому foo содержит метод с именем getBarObjects(), который возвращает массив указателей.

Поэтому я пересылаю декларацию foo в баре. Мне также нужно переслать декларацию метода, который я использую - foo:: getBarObjects(). Поскольку это возвращает массив указателей в бар, я попадаю в порочный круг.

Я не могу перенаправить строку включения, а затем просто переслать include getBarObjects(), поскольку это приводит к тому, что недопустимое имя типа недопустимо.

foo.h:

#include "bar.h"
#include <vector>

class foo {
    public:
         foo();
         ~foo();
         std::vector<bar*> getBarObjects();
    private:
         std::vector<bar*> barObjects;
}

bar.h:

class foo;
std::vector<bar*> foo::getBarObjects();        // error, doesn't know bar at this point

class bar {
    public:
        bar(foo *currentFoo);
        ~bar();
        bool dosth();
    private:
        foo *thisFoo;
}

bar.cpp:

#include "bar.h"

bool bar(foo *currentFoo) {
    thisFoo = currentFoo;
}

bool bar::dosth() {
    thisFoo->getBarObjects();        // error, pointer to inomplete class type is not allowed
}

Если я просто включу другой способ, у меня будет такая же проблема в foo lateron. Любые предложения?

Ответ 1

Вы не можете перенаправлять объявления.

Вместо этого bar.cpp должен #include как foo.h, так и bar.h. Проблема решена.

В общем случае, если вы используете последовательность:

  • Вперед объявить все типы классов
  • Определить все типы классов
  • Тела участников класса

все будет хорошо.

Ответ 2

Вам не нужно включать foo.h или bar.h друг в друга, если вы не получаете доступ к внутренним компонентам любого класса из другого заголовочного файла. Объявите классы по мере необходимости в файлах заголовков, затем включите оба файла заголовка из исходного файла.

foo.h

#include <vector>
class bar;
class foo {
    public:
         foo();
         ~foo();
         std::vector<bar*> getBarObjects();
    private:
         std::vector<bar*> barObjects;
};

bar.h

class foo;
class bar {
    public:
        bar(foo *currentFoo);
        ~bar();
        bool dosth();
    private:
        foo *thisFoo;
}

bar.cpp

#include "foo.h"
#include "bar.h"

bool bar(foo *currentFoo) {
    thisFoo = currentFoo;
}

bool bar::dosth() {
    thisFoo->getBarObjects();
}

Ответ 3

Вы забыли переслать объявление в foo.h. Вы также возвращаете значение vector из getBarObjects, которое, возможно, не то, что вы хотите, и прямое объявление функции-члена бесполезно.

Также: используйте защитные элементы заголовка. Предпочитайте соответствующий умный указатель для вашей ситуации (std::shared_ptr, unique_ptr) над необработанными указателями. Следите за const ness.