C++, two classes with mutual needs

14,264

Solution 1

I'm not seeing how forward declarations are not working for you. It looks like you need something like:

World.h:

#ifndef World_h
#define World_h

class Agent;

class World
{
    World();
    void AddAgent(Agent* agent) { agents.push_back(agent); }
    void RunAgents();
private:
    std::vector<Agent*> agents;
};

#endif

Agent.h:

#ifndef Agent_h
#define Agent_h

class World;
class Intention;

class Agent
{
    Agent(World& world_): world(world_) { world.AddAgent(this); }
    status_t Run();
private:
    World& world;
    std::vector<Intention*> intentions;
};

#endif

World.cc:

#include "World.h"
#include "Agent.h"

void World::RunAgents()
{
    for(std::vector<Agent*>::iterator i = agents.begin(); i != agents.end; ++i)
    {
        Agent& agent(**i);
        status_t stat = agent.Run();
        // do something with stat.
    }
}

// ...

Agent.cc:

#include "Agent.h"
#include "World.h"
#include "Intention.h"

// ...

Solution 2

You can solve the problem with only forward declarations, but you probably didn't separate the implementation from the declaration of the class.

If you need to call methods from the class, a full type is needed, which is why you need to include the file. You can include the file in a cpp (implementation file) without worrying about circular dependencies.

Share:
14,264

Related videos on Youtube

wmac
Author by

wmac

University researcher.

Updated on September 16, 2022

Comments

  • wmac
    wmac over 1 year

    I have converted a scientific simulation platform from Java into C++. I have tried to keep the design as much as possible the same as previous implementation. In java because of the late binding, circular dependencies are resolved at the run time. However, circular dependencies have created a hell of a mess in C++.

    1. Is there an automated tool which analyses and lists the circular includes and references? (Visual Studio 2010 only issues a huge list of nonsense errors).

    2. I have tried to use forward references wherever possible. However in some occasions both classes need functionality of the other class (i.e. call to methods which makes it impossible to use forward reference). These needs exist in Logic and if I radically change the design they will no more represent real world interactions.

      How could we implement two classes which need each other's methods and status? Is it possible to implement them in C++?

    Examples:

    • Example 1: I have a class called "World" which creates Objects of the type "Agent". Agent needs to call World methods to get information of its environment. World also needs to iterate through Agents and execute their "run" method and get their status (status updates may possibly be done reverse to solve this section of the problem but not the run method).
    • Example 2: Agents create a collection of their "Intentions". Each Agent needs to iterate through its intentions and run/update/read intention status. Intentions also need to get information about the environment through Agent (if done directly through "World" it will create complex circles again) and also info of the Agent itself.

    Below diagram shows a sub-set of classes, and some of their methods and properties:

    sub-set of classes, and some of their methods and properties

    • Mike DeSimone
      Mike DeSimone almost 12 years
      Posting the code is much more helpful than posting the errors. Posting both is best.
    • wmac
      wmac almost 12 years
      Mike, the code is near to 50,000 lines of code. I will need to cut and build a small case out of of it which reproduces the errors. Meanwhile, I did not know putting include files on top of the cpp file would solve the forward reference problem. I guess your answer will solve my problem.
  • wmac
    wmac almost 12 years
    I'll try forward references again with include files at the top of cpp files. i guess that would hopefully resolve problems.
  • wmac
    wmac almost 12 years
    Thanks Luchian. My implementation is separate but I did not move includes to the cpp files along with the forward references.
  • Mike DeSimone
    Mike DeSimone almost 12 years
    Even though it's not required by the language, it's good practice to put all the includes at the start of the file so someone reading your code can quickly know its dependencies.
  • Rev
    Rev about 8 years
    Is there a solution if you not only have references but actual instances of type A in Type B and vice versa? I get an "incomplete type" error from the compiler, which makes sense. But is there any way around it?
  • Mike DeSimone
    Mike DeSimone about 8 years
    if the utter absurdity of having an A in a B and a B in an A isn't obvious, sit down and try to work out what such a thing's memory layout would look like.