C++, two classes with mutual needs
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.
Related videos on Youtube
Comments
-
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++.
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).
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:
-
Mike DeSimone almost 12 yearsPosting the code is much more helpful than posting the errors. Posting both is best.
-
wmac almost 12 yearsMike, 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 almost 12 yearsI'll try forward references again with include files at the top of cpp files. i guess that would hopefully resolve problems.
-
wmac almost 12 yearsThanks Luchian. My implementation is separate but I did not move includes to the cpp files along with the forward references.
-
Mike DeSimone almost 12 yearsEven 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 about 8 yearsIs 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 about 8 yearsif the utter absurdity of having an
A
in aB
and aB
in anA
isn't obvious, sit down and try to work out what such a thing's memory layout would look like.