0

I believe I am having a circular dependency problem. I researched other answers but I do not understand how to use the forward declaration to fix my problem.

I have the following composition:

+------------------+
|Session  <---------------+
|                  |      |
|  +------------+  | Must know
|  |Dataset     |  |   about
|  |            |  |      ^
|  |            |  |      |
|  |            +---------+
|  |            |  |
|  |            |  |
|  +------------+  |
|                  |
+------------------+

From the code posted below, can you spot any circular dependencies or problems? I can post more code if necessary. It's a complex system and I'm trying to boil the issue down to it's most basic part.

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;

Some of the errors I get when I make Dataset aware of Session is:

Session.h Dataset in namespace bmd2 does not name a type

First try

So I tried this:

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)
{

and I still get: 'Session" in namespace bmd2 does not name a type. This is so frustrating.

  • Do your header files contain "include guards" to ensure they are never included anywhere more than once? (Perhaps you've removed them here for brevity.) These are critical! – aldo Feb 24 '14 at 06:26
  • Yes they do! They sure do. –  Feb 24 '14 at 06:27
  • Regarding the update: you need to declare `Session` in the namespace, not inside `Dataset`. – Mike Seymour Feb 24 '14 at 06:39

3 Answers3

1

Indeed, you can't have both headers including the other. Luckily, Dataset doesn't need the full definition of Session just to declare a reference to one; just declare the class (inside its namespace):

class Session;

Make sure this is in the namespace; your update indicates you've put it inside Dataset, which declares a different class in a different scope.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
1

Your dataset contains only a reference to Session, so you do not need the definition for the Session class there it is enough to just declare it in the header like:

Dataset.h

namespace bmd2 {

class Session; //class declaration

class Dataset {

  private:
    bmd::Session & session;

and the include moves to the cpp file so your class can use its methods as well in the implementation:

Dataset.cpp

#include "Session.h"

...

This is called forward declaration. See detailed info at this question.

Community
  • 1
  • 1
Csq
  • 5,775
  • 6
  • 26
  • 39
  • @jakeliquorblues: _"and I still get: 'Session" in namespace bmd2 does not name a type. This is so frustrating."_ - you put Session inside your Dataset class. That is valid (it will be a nested class) through this is not what you want now. – Csq Feb 24 '14 at 06:41
0

Since you only hold references (pointers will also work) and not actual instances, if you follow these steps closely, you will build and link fine:

  1. Make sure you have #pragma once or include guards at the top of all your .h files
  2. Create a fwd.hpp file that has forward declarations for Session and DataSet
  3. Make sure your Session.hpp and Data.hpp don't have implementation details that invoke each other's functions. If you do, put them in your .cpp files and use the appropriate cross-hpp there.
  4. In your Session.hpp and Data.hpp, only include fwd.hpp - do not include each other's headers.

This procedure will also work great if your two classes hold references or pointers to each other. As long as you keep your cross-function calls in your .cpp file (adjustments can be made for template classes if you have to invoke from the header).

kfmfe04
  • 14,936
  • 14
  • 74
  • 140