Это круговая зависимость? Как я могу это исправить?

0

Я считаю, что у меня проблема круговой зависимости. Я исследовал другие ответы, но я не понимаю, как использовать форвардную декларацию для исправления моей проблемы.

У меня есть следующий состав:

+------------------+
|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 не называет тип. Это так расстраивает.

  • 0
    Содержат ли ваши заголовочные файлы «включающие охранники», чтобы они нигде не были включены более одного раза? (Возможно, вы удалили их здесь для краткости.) Это очень важно!
  • 0
    Да, они делают! Они уверены, что делают.
Показать ещё 1 комментарий
Теги:

3 ответа

1
Лучший ответ

В самом деле, вы не можете иметь оба заголовка, в том числе и другие. К счастью, Dataset не нуждается в полном определении Session чтобы объявить ссылку на него; просто объявите класс (внутри его пространства имен):

class Session;

Убедитесь, что это место в пространстве имен; ваше обновление указывает, что вы поместили его в Dataset, который объявляет другой класс в другой области.

  • 0
    Что произойдет, если Dataset понадобится больше, чем просто декларация? Это то, что когда-либо действительно появляется в проектах C ++?
  • 0
    @jakeliquorblues: это редко случается, поскольку два класса не могут логически содержать друг друга (хотя это может произойти, если, например, вы хотите, чтобы A содержал B а B содержал vector<A> , так как для vector требуется полный тип по какой-то причине). Когда это произойдет, вам может понадобиться добавить дополнительный уровень косвенности, чтобы разорвать одну из прямых зависимостей.
1

В вашем наборе данных содержится только ссылка на Session, поэтому вам не нужно определение для класса Session достаточно просто объявить его в заголовке, например:

Dataset.h

namespace bmd2 {

class Session; //class declaration

class Dataset {

  private:
    bmd::Session & session;

и include включает в файл cpp, чтобы ваш класс мог использовать его методы и в реализации:

Dataset.cpp

#include "Session.h"

...

Это называется форвардной декларацией. См. Подробную информацию по этому вопросу.

  • 0
    @jakeliquorblues: «и я все еще получаю:« Сессия »в пространстве имен bmd2 не называет тип. Это так расстраивает. " - вы помещаете Session в свой класс Dataset. Это действительно (это будет вложенный класс), поскольку сейчас это не то, что вам нужно.
0

Поскольку вы используете только ссылки (указатели также будут работать), а не фактические экземпляры, если вы будете внимательно следить за этими шагами, вы будете строить и связывать штраф:

  1. Удостоверьтесь, что у вас есть #pragma once или включить защитников в верхней части всех файлов.h
  2. Создайте файл fwd.hpp который имеет передовые объявления для Session и DataSet
  3. Убедитесь, что у ваших Session.hpp и Data.hpp нет данных о реализации, которые вызывают функции друг друга. Если вы это сделаете, поместите их в свои.cpp файлы и используйте соответствующий cross-hpp.
  4. В ваших Session.hpp и Data.hpp только fwd.hpp - не включайте заголовки друг друга.

Эта процедура также отлично работает, если ваши два класса содержат ссылки или указатели друг на друга. До тех пор, пока вы сохраняете свои перекрестные вызовы в вашем.cpp файле (настройки могут быть сделаны для классов шаблонов, если вы должны вызывать из заголовка).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню