Я считаю, что у меня проблема круговой зависимости. Я исследовал другие ответы, но я не понимаю, как использовать форвардную декларацию для исправления моей проблемы.
У меня есть следующий состав:
+------------------+
|Session <---------------+
| | |
| +------------+ | Must know
| |Dataset | | about
| | | | ^
| | | | |
| | +---------+
| | | |
| | | |
| +------------+ |
| |
+------------------+
Из приведенного ниже кода вы можете обнаружить любые круговые зависимости или проблемы? При необходимости я могу отправить больше кода. Это сложная система, и я пытаюсь довести эту проблему до самой основной ее части.
Session.h
#include "Dataset.h"
...
namespace bmd2 {
class Session {
private:
std::vector<std::shared_ptr<bmd2::Dataset>>
datasetContainer; // error here
Dataset.h
#include "Session.h" // when I include this line I get strange errors
namespace bmd2 {
class Dataset {
private:
bmd::Session & session;
Некоторые из ошибок, которые я получаю, когда я делаю Dataset осведомленным о Сессии:
Session.h Dataset in namespace bmd2 does not name a type
Поэтому я попробовал это:
Dataset.h
// removed include
namespace bmd2 {
class Dataset {
class Session;
private:
bmd2::Session & session;
Dataset.cpp
#include "Session.h"
bmd2::Dataset::Dataset(bmd2::Session & _session,
bmd2::Logger & _logger,
const std::string & filePath,
bmd2::File::FileMode fileMode)
: session(_session), logger(_logger)
{
и я все еще получаю: "Сессия" в пространстве имен bmd2 не называет тип. Это так расстраивает.
В самом деле, вы не можете иметь оба заголовка, в том числе и другие. К счастью, Dataset
не нуждается в полном определении Session
чтобы объявить ссылку на него; просто объявите класс (внутри его пространства имен):
class Session;
Убедитесь, что это место в пространстве имен; ваше обновление указывает, что вы поместили его в Dataset
, который объявляет другой класс в другой области.
A
содержал B
а B
содержал vector<A>
, так как для vector
требуется полный тип по какой-то причине). Когда это произойдет, вам может понадобиться добавить дополнительный уровень косвенности, чтобы разорвать одну из прямых зависимостей.
В вашем наборе данных содержится только ссылка на Session
, поэтому вам не нужно определение для класса Session
достаточно просто объявить его в заголовке, например:
Dataset.h
namespace bmd2 {
class Session; //class declaration
class Dataset {
private:
bmd::Session & session;
и include включает в файл cpp, чтобы ваш класс мог использовать его методы и в реализации:
Dataset.cpp
#include "Session.h"
...
Это называется форвардной декларацией. См. Подробную информацию по этому вопросу.
Поскольку вы используете только ссылки (указатели также будут работать), а не фактические экземпляры, если вы будете внимательно следить за этими шагами, вы будете строить и связывать штраф:
#pragma once
или включить защитников в верхней части всех файлов.hfwd.hpp
который имеет передовые объявления для Session и DataSetSession.hpp
и Data.hpp
нет данных о реализации, которые вызывают функции друг друга. Если вы это сделаете, поместите их в свои.cpp файлы и используйте соответствующий cross-hpp.Session.hpp
и Data.hpp
только fwd.hpp
- не включайте заголовки друг друга.Эта процедура также отлично работает, если ваши два класса содержат ссылки или указатели друг на друга. До тех пор, пока вы сохраняете свои перекрестные вызовы в вашем.cpp файле (настройки могут быть сделаны для классов шаблонов, если вы должны вызывать из заголовка).